OpenCSV - 如何将所选列映射到Java Bean而不管顺序如何?

jsf*_*jsf 25 java csv opencsv supercsv

我有一个CSV有以下的列文件:id,fname,telephone,lname,address.

我有一个Person带班id,fnamelname数据成员.我想只将这些列映射到PersonCSV文件中的对象,并丢弃telephoneaddress列.我怎样才能做到这一点?解决方案必须随着未来添加更多列而扩展.无论列位置如何都应该工作.

在理想的解决方案中,用户只会指定要读取的列,它应该可以正常工作.

bas*_*r_p 26

您可以使用HeaderColumnNameTranslateMappingStrategy.让我们假设您CSV有以下栏目:Id,Fname,Telephone,Lname,Address为简单起见.

CsvToBean<Person> csvToBean = new CsvToBean<Person>();

Map<String, String> columnMapping = new HashMap<String, String>();
columnMapping.put("Id", "id");
columnMapping.put("Fname", "fname");
columnMapping.put("Lname", "lname");

HeaderColumnNameTranslateMappingStrategy<Person> strategy = new HeaderColumnNameTranslateMappingStrategy<Person>();
strategy.setType(Person.class);
strategy.setColumnMapping(columnMapping);

List<Person> list = null;
CSVReader reader = new CSVReader(new InputStreamReader(ClassLoader.getSystemResourceAsStream("test.csv")));
list = csvToBean.parse(strategy, reader);
Run Code Online (Sandbox Code Playgroud)

columnMapping将使用您的Person对象映射列.

  • 这个方法已经过时了,所以我写了新的答案,展示了如何使用 BeanBuilder /sf/answers/3375923211/ (3认同)
  • 是否可以将csv"2015-01-02 23:59:50"中的字符串映射到bean中的joda DateTime对象? (2认同)

agi*_*lob 5

OpenCSV的最新版本已弃用该方法parse(X, Y),建议改用BeanBuilder,因此最主要的答案是过时的。

try {
    CsvToBeanBuilder<PersonCSV> beanBuilder = new CsvToBeanBuilder<>(new InputStreamReader(new FileInputStream("your.csv")));

    beanBuilder.withType(PersonCSV.class);
    // build methods returns a list of Beans
    beanBuilder.build().parse().forEach(e -> log.error(e.toString()));

} catch (FileNotFoundException e) {
    log.error(e.getMessage(), e);
}
Run Code Online (Sandbox Code Playgroud)

通过此方法,您可以清理代码并删除MappingStrategy(如果您喜欢意大利面条,仍然可以使用它),因此可以按以下方式注释CSV类:

@CsvDate("dd/MM/yyyy hh:mm:ss")
@CsvBindByName(column = "Time Born", required = true)
private Date birthDate;
Run Code Online (Sandbox Code Playgroud)

  • 如何忽略未映射的 CSV 列?我的意思是,如果 CSV 中有 10 列,而我只想读取其中的 5 列(这 5 列在 bean 中),那么呢?目前它抛出异常“数据字段数量与标头数量不匹配。” (3认同)

Jam*_*ett 4

我不能代表 opencsv,但是使用Super CSV可以轻松实现这一点,它有两个不同的阅读器,支持部分阅读(忽略列)以及读入 Javabean。CsvDozerBeanReader甚至能够进行深度和基于索引的映射,因此您可以映射到嵌套字段。

我们(Super CSV 团队)刚刚发布了 2.0.0 版本,可以从 Maven 中心或 SourceForge 获取。

更新

下面是一个示例(基于您创建的 GitHub 项目中的测试),它使用 Super CSV 而不是 opencsv。请注意,CSV 首选项需要surroundingSpacesNeedQuotes启用该标志,因为您的示例 CSV 文件无效(字段之间有空格 - 空格被视为 CSV 中数据的一部分)。

ICsvBeanReader beanReader = null;
try {
    beanReader = new CsvBeanReader(
            new InputStreamReader(
                    ClassLoader.getSystemResourceAsStream("test.csv")),
            new CsvPreference.Builder(CsvPreference.STANDARD_PREFERENCE)
                    .surroundingSpacesNeedQuotes(true).build());

    List<String> columnsToMap = Arrays.asList("fname", "telephone", "id");

    // read the CSV header (and set any unwanted columns to null)
    String[] header = beanReader.getHeader(true);
    for (int i = 0; i < header.length; i++) {
        if (!columnsToMap.contains(header[i])) {
            header[i] = null;
        }
    }

    Person person;
    while ((person = beanReader.read(Person.class, header)) != null) {
        System.out.println(person);
    }

} finally {
    beanReader.close();
}
Run Code Online (Sandbox Code Playgroud)