使用OpenCSV在Java中读写CSV


介绍
这是专门 针对Java CSV读写库 的简短系列文章的最后一篇,也是上一篇文章( 使用Apache Commons CSV用Java读写CSV) 的直接延续。
OpenCSV
OpenCSV
是最简单易懂的CSV解析器之一,它使用标准
Reader
/
Writer
类并
CSVReader
在顶部提供实现。
就像Apache Commons CSV一样, OpenCSV 具有Apache 2.0许可证。在下载并决定是否使用OpenCSVs解析器之前,您可以浏览 源代码和Java文档 ,甚至查看其git存储库中包含的JUnit测试套件。
OpenCSV也包含在 MVNRepository中 ,使依赖关系管理变得简单明了。
该
CSVReader
允许一次读取一个记录,多个记录列表或作为一个迭代器,使得它在读取数据的可用性方面灵活。该库还包括方便的功能,例如读取,写入和写入Bean,以及使用标题行将CSV直接映射到Java Map。
OpenCSV没有像Apache Commons CSV一样广泛的预定义格式。它依赖于两个解析器:
- CSVParser- 在OpenCSV中定义的原始解析器。这适用于大多数简单的解析实例,但是如果记录中定义了转义字符,则失败。
-
RFC4180Parser-
与
CSVFormat.RFC4180
Apache Commons CSV中的解析器类似。适用于根据RFC 4180规范进行格式设置的CSV文件。此版本的解析器将开始和结束引号之间的所有字符都视为内容,双引号字符除外,该字符需要用另一个双引号进行转义。
使用OpenCSV读取CSV
使用OpenCSV读取CSV的速度比使用Apache Commons CSV读取的速度要快,因为
CSVWriter
使用该
CSVToBean.parse()
方法时,将CSV实现为多线程的。
该
CSVReader
使用还实现
Java的可迭代
,所以它可以管理基于您选择的实现方法内存和时间的限制。
OpenCSV有两种用于读取CSV的对象类型 -CSVReader 及其子类 CSVReaderHeaderAware 。
CSVReader
与它的Apache Commons CSV
CSVParser
对应版本相似,可用于简单和复杂的解析方案。
要遍历CSV文件中的每条记录,其中
record
将是一个字符串数组,其逗号分隔的值分为多个单独的字段:
CSVReader csvReader = new CSVReader (new InputStreamReader(csvFile.getInputStream()));
while ((record = csvReader.readNext()) != null) {
// do something
}
如果CSV由逗号以外的字符分隔,则可以改用两参数构造函数,并指定要
CSVReader
使用的分隔符。
例如,如果您的CSV包含制表符分隔的值,则可以
CSVReader
如下初始化:
CSVReader csvReader = new CSVReader(new InputStreamReader(csvFile.getInputStream()), '\t');
OpenCSV还有一种解析CSV文件的更复杂的方法,其中涉及实现bean来映射CSV中的字段,然后使用注释来基于基于标题的注释或基于位置的注释来标识记录的类型。
这有帮助,因为它允许将CSV记录作为公共数据集而不是单个字段的集合进行处理。
如果正在处理的文件的标题名称一致,则可以使用批注对列进行
@CSVBindByName
批注,并允许OpenCSV负责处理解析数据的映射和复制方面。
例如我们的树数据集:
public class Trees {
@CSVBindByName
private int index;
@CSVBindByName
private int girth;
@CSVBindByName
private int height;
@CSVBindByName
private int volume;
public int getIndex() {
return this.index;
public void setIndex(int newIndex) {
this.index = newIndex;
}
只要您的CSV文件在我们的类声明中包含一个以变量名命名的头,OpenCSV便可以解析数据并将其读取到相应的元素中,并自动处理类型转换:
List<Trees> treeParser = new CSVToBeanBuilder(FileReader("somefile.csv")).withType(Trees.class).build().parse();
可以在需要的地方将验证添加到getter和setter方法中,并且可以通过
required
在注释上设置标志来指定必填字段。
如果标题名称与变量名称略有不同,则也可以在注释中设置String。在我们的示例中,当列名不同时映射标头名称的功能非常有用,因为我们的实际数据集包含字段的度量单位,以及标准Java变量名称中不允许的空格和标点符号。
在这种情况下,可以使用注释指定标志和映射:
...
@CSVBindByName (column = "Girth (in)", required = true)
private int girth;
...
如果您的CSV文件没有标题,则可以按列位置和
@CSVBindByPosition
注释进行映射。
请记住,OpenCSV位置从0开始:
public class Trees{
@CSVBindByPosition(position = 0, required = true)
private int index;
@CSVBindByPosition(position = 1, required = true)
private int girth;
@CSVBindByPosition(position = 2)
private int height;
@CSVBindByPosition(position = 3)
private int volume;
}
如果要处理更复杂的场景,则可以使用 MappingStrategy接口 实现一个类,并定义适合您的解析场景的转换或映射架构。
使用OpenCSV编写CSV
在将数据写入CSV文件时,OpenCSV比Apache Commons CSV具有更多选项。它允许您从字符串数组中写入,或者从对象列表中写入。
从对象列表进行写入需要事先初始化和声明对象。为了简单起见,让我们考虑使用字符串数组。
要使用字符串数组中的数据生成CSV文件,请执行以下操作:
CSVWriter csvWriter = new CSVWriter(new FileWriter("new.csv"), ',');