Java使用OpenCSV读取CSV文件返回null及行数缺失问题排查
根因确认
你的判断完全正确,解决方案合理。
使用@CsvBindByName注解做字段映射时,OpenCSV的CsvToBeanBuilder只要指定了对应的映射模型类,会默认将CSV第一行识别为表头行,自动匹配注解中配置的列名,且不会将表头解析为数据行。你额外配置的.withSkipLines(1)会在此基础上再多跳过一行有效数据,也就是CSV中id为1的第一条数据,最终导致返回结果少一行。
同时你最初的代码将返回值泛型写为List<String>,但csvToBean.parse()实际返回的是映射模型类的实例列表,强转过程会导致字段取值异常,你修改返回值泛型的操作也是必要的。
代码优化建议
你修改后的代码还可以进一步优化泛型实现,提升类型安全性,避免后续类型转换的额外操作,优化后的代码参考如下:
public static <T> List<T> readDataLineByLine(String path, Class<T> classModel) { // 使用try-with-resources自动关闭Reader,避免资源泄漏 try (Reader reader = Files.newBufferedReader(Paths.get(path))) { return new CsvToBeanBuilder<T>(reader) .withType(classModel) .withSeparator(',') .withIgnoreLeadingWhiteSpace(true) .build() .parse(); } catch (IOException ex) { Log.error(ex.toString()); return null; } }
另外日期类型的解析不需要手动在getter中实现,可以直接使用OpenCSV提供的@CsvDate注解简化代码,修改模型类的date字段配置即可:
@CsvBindByName(column = "date") @CsvDate(value = "dd/MM/yyyy") private Date date;
OpenCSV使用最佳实践
- 解析大文件时可以配置异常捕获策略,添加
.withThrowExceptions(false)配置,避免单行数据格式错误导致整个解析任务终止,解析完成后可通过getCapturedExceptions()方法获取所有解析失败的行信息单独处理。 - 数值类型字段如果CSV中可能存在空值,不要使用int、double等基础类型,改用Integer、Double等包装类型,避免空值拆箱抛出空指针异常。
- 如果CSV表头命名和模型类字段命名遵循统一规则(如下划线转驼峰),可以配置全局命名转换策略,不需要每个字段都手动指定
column属性,减少冗余代码。 - 对于有特殊格式要求的字段(如自定义枚举、金额等),可以自定义
CsvCustomBindByName注解配合转换器实现自动解析,不用在业务代码中单独做格式转换。
内容的提问来源于stack exchange,提问作者ArCiGo
相关产品推荐
相关产品推荐

