介绍
这是专门针对Java读写CSV的库的简短系列文章的第二篇,也是上一篇文章“ Core Java读写CSV”的直接续篇。
Apache Commons CSV
在Apache的百科全书CSV库是Apache软件基金会的版本在Java CSV解析器。根据项目摘要,它试图“提供一个用于读取和写入各种类型CSV文件的简单界面”。
与所有与Apache关联的库一样,它使用Apache许可证运行,这意味着可以自由使用,分发和修改它。
Apache Commons允许开发人员定义自己的格式,但是通过CSVFormat类提供了一组预定义的格式。
这些预定义的格式是:
RFC4180-由RFC 4180定义的逗号分隔格式。默认-与RFC4180格式相似,但是允许在数据行之间插入空行。如果在使用Apache Commons CSV库定义解析器时未另外指定,则使用此格式。EXCEL-与RFC 4180类似,但是允许缺少列名,并且忽略空行。TDF-CSV文件的预定义格式,用制表符(t
)代替逗号分隔。MYSQL-MySqlSELECT INTO OUTFILE
和LOAD DATA INFILE
操作支持的格式。ORACLE-Oracle SQL加载程序使用的CSV格式。INFORMIX_UNLOAD和INFORMIX_UNLOAD_CSV-定义为与IBM Informix可嵌入数据库一起使用的特殊格式。MONGODB_CSV和MONGODB_TSV-与杨木NoSQL MongoDB数据库配合使用,分别用于逗号分隔和制表符分隔的值。POSTGRESQL_CSV和POSTGRESQL_TEXT-PostgreSQL数据库支持的格式。
如果您需要一个非常简单的解决方案,则可能不适合使用Apache Commons CSV。该实现旨在提供最大的灵活性,这使源代码等于大约30,000行,并且在某些情况下很难理解。
但是,如果您确实需要涵盖多种格式,则Apache Commons是一个值得信赖的库,可以很好地进行定期维护和更新,其中包含大量的Java Docs和开发人员文档以支持初学者。
它包含在Maven Central存储库中,没有外部依赖关系。
使用Apache Commons CSV读取CSV
Apache Commons库提供了几种访问CSV文件中各个字段的方法。如果您使用的是Excel之类的应用程序,则Excel格式的CSV可能会有标题。
但是,如果您使用CSV作为基本的逗号分隔文本集,以便在系统之间传输数据或将其馈入另一个处理应用程序,则该文件可能包含从第一行本身开始的数据,而没有标题。Apache Commons CSV库考虑了这两种情况。
如果CSV文件不包含标题,或者不确定是否包含标题,则可以使用索引访问记录。由于CSVRecord
实现了Java Iterable Interface,因此即使使用Excel和大多数其他应用程序打开CSV索引,其索引也从1开始,但索引是基于0的:
CSVParser csvParser = CSVFormat.DEFAULT.parse(new InputStreamReader(csvFile.getInputStream()));for (CSVRecord record : csvParser) {String field_1 = record.get(0);String field_2 = record.get(1);...}
如果您确定需要解析的CSV文件具有标题,并且知道处理前的标题格式,则可以使用标题列字符串来提取记录。
让我们考虑一个带有树数据的示例CSV文件,并将其称为“树数据CSV”,以供本文将来参考:
要引用数据的每一行,我们可以像上一个示例一样使用索引或列标题:
InputStreamReader input = new InputStreamReader(csvFile.getInputStream());CSVParser csvParser = CSVFormat.EXCEL.withFirstRecordAsHeader().parse(input);for (CSVRecord record : csvParser) {String field_1 = record.get("Index");String field_2 = record.get("Girth (in)");String field_3 = record.get("Height (ft)");String field_4 = record.get("Volume (ft)");}
如果要读取不包含标题行的文件,想要定义自己的标题或使索引混乱,则Apache Commons还允许定义标题以进行解析。
.withFirstRecordAsHeader()
您可以手动定义标题,而不是在定义CSV文件格式时使用该方法。例如,如果要避免在树数据文件的标题中引用度量单位,则可以重新定义标题以使用自己的字符串值:
CSVParser csvParser = CSVFormat.REF4180.withHeader("Index", "Girth", "Height", "Volume");for (CSVRecord record : csvParser) {String field_2 = record.get("Girth");}
如果您的CSV文件包含标题,但是您想定义自己的标题并跳过读取文件中的标题,请使用.readNext()
以跳过第一行:
CSVRecord header = csvParser.readNext();// read the other rows in a loop as usual
如果需要跨多个类使用定义,则也可以使用枚举来定义标头,如本示例所示:
public enum treeHeader {Index, Girth, Height, Volume}...CSVParser csvParser = CSVFormat.DEFAULT.withHeader(treeHeader.class).parse(input);// read rows
Apache Commons CSV库提供了一些其他方法来简化解析,包括:
.getRecordNumber()
-返回分配给CSV文件中记录的编号。.isConsistent()
-可用于错误处理,根据当前记录的大小是否与标题行的大小匹配,返回True或False。.size()
-可用于确定记录中的值数。.toString()
-以字符串形式返回记录。当您需要将整个行存储为String以便以后进行处理,哈希或比较时很有用。
使用Apache Commons CSV编写CSV
Apache Commons CSV库主要集中于从CSV文件读取数据。在编写时,我们的核心Java实现非常熟悉用户指南中推荐的方法。
但是,还有一些有用的附加功能,例如在打印时定义标头以及直接从JDBCResultSet
对象打印的功能。
在CSVPrinter
类实现Flushable
和Closeable
接口,使得其行为类似于通常的Java的扩展Writer
或StringWriter
。
例如,生成我们的树数据CSV:
CSVPrinter csvPrinter = new CSVPrinter(stringWriter, CSVFormat.DEFAULT.withHeader("Index", "Girth", "Height", "Volume"));csvPrinter.printRecord("1", "8.3", "70", "10.3");csvPrinter.flush();
该方法.withHeader()
接受标头的字符串值作为参数。
如果要生成不带标题的CSV,则可以直接使用new CSVPrinter(stringWriter, CSVFormat.DEFAULT);
。
如果要使用现有JDBC的列标题ResultSet
进行打印,则Apache Commons CSV接受aResultSet
作为其.withHeader()
方法的参数:
CSVPrinter csvPrinter = CSVFormat.RFC4180.withHeader(treeDataResultSet).print(out);csvPrinter.printRecords(treeDataResultSet);
如果CSVFormat
您使用允许空行,则可以用来csvPrinter.println()
在数据行之间打印空白行。
除了ResultSet
,该.printRecords()
方法还能够与工作可迭代数组或集合字符串传递给该方法采用可变参数。
结论
Apache Commons CSV尝试提供一个简单的界面来读写各种类型的CSV文件。
该实现旨在提供最大的灵活性,这使得源代码在某些情况下很难理解。
但是,如果您确实需要涵盖多种格式,则Apache Commons是一个值得信赖的库,可以很好地进行定期维护和更新,其中包含大量的Java Docs和开发人员文档以支持初学者。
在Core Java中读写CSV使用OpenCSV在Java中读写CSV