如何使用OpenCSV提取输入CSV文件的表头信息
问题描述
OpenCSV是一款用于读写CSV文件的Java类库。需求为在处理CSV的数据记录前读取并提取文件表头,根据列名判断后续需要映射的实体类,求具体实现方式。
当前业务代码如下,注释标注位置即为需要获取表头信息的节点:
BufferedReader in = new BufferedReader(new InputStreamReader(file.getInputStream())); CSVParser csvParser = new CSVParserBuilder().withSeparator('\t').build(); CSVReader csvReader = new CSVReaderBuilder(in).withCSVParser(csvParser).build(); // 后续代码逻辑依赖列名判断,需要在此处获取表头信息,确认是映射为Book实体类还是其他实体类 CsvToBean<Book> csvToBeanConverter = new CsvToBeanBuilder<Book>(csvReader).withType(Book.class).build(); Iterator<Book> bookIter = csvToBeanConverter.iterator(); bookIter.forEachRemaining(book -> { System.out.println("book: " + book); });
问题补充
- 更新1:经测试OpenCSV和apache-commons-csv两个常用CSV解决方案都存在一定不足,个人常用CSV类库推荐类的主观内容请发布在评论区,不要作为正式回答提交。
- 更新2:网上流传的《如何在Java中读取CSV表头并存入列表》一文提到的方案属于权宜方案:如果要配合
CsvToBean使用,该方案需要对BufferedReader调用mark()和reset()方法,会限制支持的表头最大长度,超出限制时会抛出异常,不推荐使用。
实现方案
直接调用CSVReader实例的readNext()方法即可读取第一行的表头内容,不需要操作流的mark/reset逻辑,也不会出现表头长度超限的问题。读取完表头后再构建CsvToBean实例即可,OpenCSV会自动从当前读取位置(即表头下的第一行数据)开始解析实体,不会重复读取表头行。
修改后的可运行代码示例:
BufferedReader in = new BufferedReader(new InputStreamReader(file.getInputStream())); CSVParser csvParser = new CSVParserBuilder().withSeparator('\t').build(); CSVReader csvReader = new CSVReaderBuilder(in).withCSVParser(csvParser).build(); // 读取第一行作为表头 String[] headers = csvReader.readNext(); // 在此处根据headers数组中的列名判断映射的实体类型,例如判断是否包含Book实体的专属字段 boolean matchBookEntity = Arrays.stream(headers).anyMatch("bookId"::equals); if (matchBookEntity) { CsvToBean<Book> csvToBeanConverter = new CsvToBeanBuilder<Book>(csvReader).withType(Book.class).build(); Iterator<Book> bookIter = csvToBeanConverter.iterator(); bookIter.forEachRemaining(book -> { System.out.println("book: " + book); }); } else { // 此处编写映射其他实体类的逻辑 }
注意事项
- 该方案全程复用同一个
CSVReader实例,不需要回退输入流,没有表头长度限制,不会触发mark/reset相关的异常 - 拿到
headers数组后可以先做表头合法性校验,确认必填列存在后再继续解析后续数据,避免无意义的IO读取 - 如果待处理的CSV文件本身没有设置表头行,不要使用该方式读取,否则会把第一行业务数据当成表头丢失
内容的提问来源于stack exchange,提问作者Daniel S.
相关产品推荐
相关产品推荐

