使用OpenCSV在Java中读写CSV

Reading and Writing CSVs in Java with OpenCSV

介绍

这是专门针对Java CSV读写库的简短系列的最后一篇文章,也是上一篇文章的直接续篇-使用Apache Commons CSV的Java CSV读写。

打开CSV

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-与Apache Commons CSV中的CSVFormat.RFC4180解析器相似。 适用于根据RFC 4180规范进行格式设置的CSV文件。此版本的解析器将开头和结尾引号之间的所有字符都视为内容,双引号字符除外,后者需要用另一个双引号进行转义。

  • 使用OpenCSV读取CSV

    用OpenCSV读取CSV比使用Apache Commons CSV读取CSV更快,因为在使用CSVToBean.parse()方法时,CSVWriter被实现为多线程。

    CSVReader也使用Java Iterable实现,因此可以根据您选择的实现方法来管理内存和时间限制。

    OpenCSV有两种用于读取CSV的对象类型-CSVReader及其子类CSVReaderHeaderAware。

    CSVReader与它的Apache Commons CSV CSVParser相似,可以用于简单和复杂的解析方案。

    要遍历CSV文件中的每条记录,其中record将是一个字符串数组,其逗号分隔的值分为多个单独的字段:

    1
    2
    3
    4
    CSVReader csvReader = new CSVReader (new InputStreamReader(csvFile.getInputStream()));
    while ((record = csvReader.readNext()) != null) {
        // do something
    }

    如果CSV由逗号以外的字符分隔,则可以改用两参数构造函数,并指定要使用CSVReader的分隔符。

    例如,如果CSV包含制表符分隔的值,则可以按以下方式初始化CSVReader

    1
    CSVReader csvReader = new CSVReader(new InputStreamReader(csvFile.getInputStream()), '\t');

    OpenCSV还有一种解析CSV文件的更复杂的方法,其中涉及实现bean来映射CSV中的字段,然后使用注释通过基于标题的注释或基于位置的注释来标识记录的类型。

    这有帮助,因为它允许将CSV记录作为通用数据集而不是单个字段的集合进行处理。

    如果正在处理的文件的标题名称一致,则可以使用@CSVBindByName批注对列进行批注,并允许OpenCSV处理处理解析数据的映射和复制方面。

    例如我们的树数据集:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    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便可以解析数据并将其读入相应的元素,并自动处理类型转换:

    1
    List<Trees> treeParser = new CSVToBeanBuilder(FileReader("somefile.csv")).withType(Trees.class).build().parse();

    可以在需要的地方将验证添加到getter和setter方法中,并且可以通过在注释上设置required标志来指定必填字段。

    如果标题名称与变量名称略有不同,则也可以在注释中设置String。 在我们的示例中,当列名不同时,能够映射标头名称的功能非常有用,因为我们的实际数据集包含字段的度量单位,以及标准Java变量名称中不允许的空格和标点符号。

    在这种情况下,可以使用注释指定标志和映射:

    1
    2
    3
    4
    ...
        @CSVBindByName (column ="Girth (in)", required = true)
        private int girth;
    ...

    如果CSV文件没有标题,则可以按列位置与@CSVBindByPosition批注进行映射。

    请记住,OpenCSV位置从0开始:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    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文件,请执行以下操作:

    1
    2
    3
    4
    CSVWriter csvWriter = new CSVWriter(new FileWriter("new.csv"), ',');
    String[] records ="Index.Girth.Height.Volume".split(".");
    csvWriter.writeNext(records);
    csvWriter.close();

    OpenCSV的概念是CSV不仅是逗号分隔的值; 它允许您定义要在文件中使用哪个定界符作为CSVWriter构造函数中的参数。

    同样,在定义String数组时,您可能会发现声明一个String然后基于定界符将其分隔为多个值很有用。 当您需要将选定的数据行子集从一个CSV或数据库文件复制到另一个时,此功能特别有用。

    初始化CSVWriter时,必须使用FileWriterWriter。 仅使用一个参数初始化writer会生成一个默认的逗号分隔文件。

    对于特定的用例,还有一些其他参数:

  • Char separator-分隔符。 如果未声明,则默认分隔符将为逗号。

  • Char quotechar-引号字符。 如果您的数据集包含带有逗号的值作为数据集的一部分,并且您需要生成逗号分隔的文件,则将使用此方法。 通常,双引号,单引号或斜杠都用作引号字符。

  • Char escapechar-通常用于转义quotechar

  • String lineend-确定数据行结尾的字符串或字符。

  • 您可以构造包含所有可选参数的CSVWriter

    1
    2
    CSVWriter csvWriter = new CSVWriter(new FileWriter("new.csv"),",","'","/","
    "
    );

    CSVWriter还具有一些字段,您可以将这些字段作为参数传递给构造函数。 您可以将这些值定义为常量,并在代码库中重用字符和字符串以保持一致性。

    例如,在声明之后:

    1
    2
    3
    4
    5
    CSVWriter.DEFAULT_SEPARATOR =",";
    CSVWriter.DEFAULT_QUOTE_CHARACTER ="'";
    CSVWriter.DEFAULT_ESCAPE_CHARACTER ="/";
    CSVWriter.DEFAULT_LINE_END ="
    "
    ;

    您可以使用:

    1
    CSVWriter csvWriter = new CSVWriter(new FileWriter("new.csv"), CSVWriter.DEFAULT_SEPARATOR, CSVWriter.DEFAULT_QUOTE_CHARACTER, CSVWriter.DEFAULT_ESCAPE_CHARACTER, CSVWriter.DEFAULT_LINE_END);

    如果未在构造函数中明确定义值,则可以使用默认值使用OpenCSV并直接调用:

    1
    CSVWriter csvWriter = new CSVWriter(new FileWriter("new.csv"));

    因此,如果您的数据包含带有用户名和地址的行,例如:JohnDoe,19/2,ABC Street,Someplace,则您需要使用的实际字符串格式是" JohnDoe"," 19 // 2 /,ABC Street /,Someplace"。

    结论

    OpenCSV是最简单易懂的CSV解析器之一,它使用标准的Reader / Writer类并在顶部提供了CSVReader实施。

  • 在Core Java中读写CSV

  • 使用Apache Commons CSV用Java读写CSV