Introduction to OpenCSV – OpenCSV简介

最后修改: 2018年 3月 12日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.介绍

In this quick tutorial, we’ll introduce OpenCSV 4, a fantastic library for writing, reading, serializing, deserializing, and/or parsing .csv files. Then we’ll go through several examples demonstrating how to set up and use OpenCSV 4 for our endeavors.

在这个快速教程中,我们将介绍OpenCSV 4,一个用于编写、阅读、序列化、反序列化和/或解析.csv文件的神奇库。然后,我们将通过几个例子来演示如何设置和使用OpenCSV 4来完成我们的工作。

2. Set Up

2.设置

First, we’ll add OpenCSV to our project by way of a pom.xml dependency:

首先,我们将通过pom.xml依赖性的方式将OpenCSV添加到我们的项目中。

<dependency>
    <groupId>com.opencsv</groupId>
    <artifactId>opencsv</artifactId>
    <version>4.1</version>
</dependency>

The .jars for OpenCSV can be found at the official site or through a quick search at the Maven Repository.

OpenCSV的.jars可以在官方网站上找到,或者通过Maven仓库的快速搜索。

Our .csv file will be really simple; we’ll keep it to two columns and four rows:

我们的.csv文件将非常简单;我们将把它保持在两列和四行。

colA,colB
A,B
C,D
G,G
G,F

3. To Bean or Not to Bean

3.要不要吃Bean

After adding OpenCSV to our pom.xml, we can implement CSV-handling methods in two convenient ways:

在将OpenCSV添加到我们的pom.xml之后,我们可以通过两种方便的方式实现CSV处理方法。

  1. using the handy CSVReader and CSVWriter objects (for simpler operations)
  2. using CsvToBean to convert .csv files into beans (which are implemented as annotated plain-old-java-objects)

We’ll stick with synchronous (or blocking) examples for this article, so we can focus on the basics.

在本文中,我们将坚持使用同步(或阻塞)的例子,因此我们可以专注于基础知识。

Remember, a synchronous method will prevent surrounding or subsequent code from executing until it’s done. Production environments will likely use asynchronous (or non-blocking) methods that will allow other processes or methods to complete while the asynchronous method finishes up.

请记住,一个异步方法将阻止周围或后续代码的执行,直到它完成。生产环境可能会使用异步(或非阻塞)方法,在异步方法完成后,允许其他进程或方法完成。

We’ll dive into asynchronous examples for OpenCSV in a future article.

我们将在未来的文章中深入研究OpenCSV的异步例子。

3.1. The CSVReader

3.1.CSVReader

Let’s explore CSVReader through the supplied readAll() and readNext() methods. We’ll look at how to use readAll() synchronously:

让我们通过提供的readAll()readNext()方法探索CSVReader。我们将看看如何同步地使用readAll()。

public List<String[]> readAllLines(Path filePath) throws Exception {
    try (Reader reader = Files.newBufferedReader(filePath)) {
        try (CSVReader csvReader = new CSVReader(reader)) {
            return csvReader.readAll();
        }
    }
}

Then we can call that method by passing in a file Path:

然后我们可以通过传入一个文件Path来调用该方法。

public List<String[]> readAllExample() throws Exception {
    Path path = Paths.get(
      ClassLoader.getSystemResource("csv/twoColumn.csv").toURI())
    );
    return CsvReaderExamples.readAllLines(path);
}

Similarly, we can abstract readNext(), which reads a supplied .csv line by line:

类似地,我们可以抽象出readNext(),它逐行读取提供的.csv

public List<String[]> readLineByLine(Path filePath) throws Exception {
    List<String[]> list = new ArrayList<>();
    try (Reader reader = Files.newBufferedReader(filePath)) {
        try (CSVReader csvReader = new CSVReader(reader)) {
            String[] line;
            while ((line = csvReader.readNext()) != null) {
                list.add(line);
            }
        }
    }
    return list;
}

Finally, we can call that method here by passing in a file Path:

最后,我们可以在这里通过传入一个文件Path:来调用该方法。

public List<String[]> readLineByLineExample() throws Exception {
    Path path = Paths.get(
      ClassLoader.getSystemResource("csv/twoColumn.csv").toURI())
    );
    return CsvReaderExamples.readLineByLine(path);
}

Alternatively, for greater flexibility and configuration options, we can use CSVReaderBuilder:

另外,为了获得更大的灵活性和配置选项,我们可以使用CSVReaderBuilder

CSVParser parser = new CSVParserBuilder()
    .withSeparator(',')
    .withIgnoreQuotations(true)
    .build();

CSVReader csvReader = new CSVReaderBuilder(reader)
    .withSkipLines(0)
    .withCSVParser(parser)
    .build();

CSVReaderBuilder allows us to skip the column headings and set parsing rules through CSVParserBuilder.

CSVReaderBuilder允许我们跳过列标题,通过CSVParserBuilder设置解析规则。

Using CSVParserBuilder, we can choose a custom column separator, ignore or handle quotations marks, state how we’ll handle null fields, and how we’ll interpret escaped characters. For more information on these configuration settings, please refer to the official specification docs.

使用CSVParserBuilder,我们可以选择一个自定义的列分隔符,忽略或处理引号,说明我们将如何处理空字段,以及我们将如何解释转义字符。有关这些配置设置的更多信息,请参考官方规范docs

As always, we need to remember to close all our Readers to prevent memory leaks.

像往常一样,我们需要记住关闭所有的Readers以防止内存泄漏。

3.2. The CSVWriter

3.2.CSVWriter

CSVWriter similarly supplies the ability to write to a .csv file all at once or line by line.

CSVWriter同样提供了向.csv文件一次性或逐行写入的能力。

Let’s see how to write to a .csv line by line:

让我们看看如何逐行写入.csv中。

public String writeLineByLine(List<String[]> lines, Path path) throws Exception {
    try (CSVWriter writer = new CSVWriter(new FileWriter(path.toString()))) {
        for (String[] line : lines) {
            writer.writeNext(array);
        }
    return Helpers.readFile(path);
}

Then we’ll specify where we want to save that file, and call the method we just wrote:

然后我们将指定我们要保存该文件的位置,并调用我们刚才写的方法。

public String writeLinebylineExample() throws Exception {
    Path path = Paths.get(
      ClassLoader.getSystemResource("csv/writtenOneByOne.csv").toURI()
    ); 
    return CsvWriterExamples.writeLineByLine(Helpers.fourColumnCsvString(), path); 
}

We can also write our .csv all at once by passing in a List of String arrays representing the rows of our .csv:

我们也可以通过传入代表.csv的行的List数组,一次性写出我们的.csv

public String writeAllLines(List<String[]> lines, Path path) throws Exception {
    try (CSVWriter writer = new CSVWriter(new FileWriter(path.toString()))) {
        writer.writeAll(stringArray);
    }
    return Helpers.readFile(path);
}

Finally, here’s how we call it:

最后,我们是这样称呼它的。

public String writeAllExample() throws Exception {
    Path path = Paths.get(
      ClassLoader.getSystemResource("csv/writtenAll.csv").toURI()
    ); 
    return CsvWriterExamples.writeAllLines(Helpers.fourColumnCsvString(), path);
}

3.3. Bean-Based Reading

3.3.基于Bean的阅读

OpenCSV is able to serialize .csv files into preset and reusable schemas implemented as annotated Java pojo beans. CsvToBean is constructed using CsvToBeanBuilder. As of OpenCSV 4, CsvToBeanBuilder is the recommended way to work with com.opencsv.bean.CsvToBean.

OpenCSV能够将.csv文件序列化为预设的、可重用的模式,并以注释的JavapojoBean来实现。CsvToBean是使用CsvToBeanBuilder构建的。从OpenCSV 4开始,CsvToBeanBuilder是使用com.opencsv.bean.CsvToBean的推荐方式。

Here’s a simple bean we can use to serialize our two-column .csv from earlier:

这里有一个简单的Bean,我们可以用来序列化我们前面的两列.csv

public class SimplePositionBean  {
    @CsvBindByPosition(position = 0)
    private String exampleColOne;

    @CsvBindByPosition(position = 1)
    private String exampleColTwo;

    // getters and setters
}

Each column in the .csv file is associated with a field in the bean. We can perform the mappings between .csv column headings using the @CsvBindByPosition or the @CsvBindByName annotations, which specify a mapping by position or heading string match, respectively.

.csv文件中的每一列都与Bean中的一个字段相关。我们可以使用@CsvBindByPosition@CsvBindByName注解来执行.csv列标题之间的映射,它们分别通过位置或标题字符串匹配来指定映射。

First, we’ll create a superclass called CsvBean, which will allow us to reuse and generalize the methods we’ll build below:

首先,我们将创建一个名为CsvBean的超类,这将使我们能够重用和泛化我们将在下面构建的方法。

public class CsvBean { }

Here’s an example child class:

下面是一个儿童类的例子。

public class NamedColumnBean extends CsvBean {

    @CsvBindByName(column = "name")
    private String name;

    // Automatically infer column name as 'Age'
    @CsvBindByName
    private int age;

    // getters and setters
}

Next, we’ll abstract a synchronously returned List using the CsvToBean:

接下来,我们将使用CsvToBean抽象出一个同步返回的List

public List<CsvBean> beanBuilderExample(Path path, Class clazz) throws Exception {
    CsvTransfer csvTransfer = new CsvTransfer();

    try (Reader reader = Files.newBufferedReader(path)) {
        CsvToBean<CsvBean> cb = new CsvToBeanBuilder<CsvBean>(reader)
         .withType(clazz)
         .build();

        csvTransfer.setCsvList(cb.parse());
    }
    return csvTransfer.getCsvList();
}

Then we pass in our bean (clazz) and in doing so, we associate the fields of our beans with the respective columns of our .csv rows.

然后我们传入我们的Bean(clazz),在这样做的时候,我们将Bean的字段与.csv行的相应列联系起来。

We can call that here using the SimplePositionBean subclass of the CsvBean we wrote above:

我们可以在这里使用我们上面写的SimplePositionBean子类的CsvBean来调用。

public List<CsvBean> simplePositionBeanExample() throws Exception {
    Path path = Paths.get(
      ClassLoader.getSystemResource("csv/twoColumn.csv").toURI()); 
    return BeanExamples.beanBuilderExample(path, SimplePositionBean.class); 
}

We can also call it here using the NamedColumnBean, another subclass of the CsvBean:

我们也可以在这里使用NamedColumnBean,CsvBean的另一个子类调用它。

public List<CsvBean> namedColumnBeanExample() throws Exception {
    Path path = Paths.get(
      ClassLoader.getSystemResource("csv/namedColumn.csv").toURI()); 
    return BeanExamples.beanBuilderExample(path, NamedColumnBean.class);
}

3.4. Bean-Based Writing

3.4.基于Bean的写作

Finally, let’s take a look at how to use the StatefulBeanToCsv class to write to a .csv file:

最后,让我们看看如何使用StatefulBeanToCsv类来向.csv文件写入。

public String writeCsvFromBean(Path path) throws Exception {

    List<CsvBean> sampleData = Arrays.asList(
        new WriteExampleBean("Test1", "sfdsf", "fdfd"),
        new WriteExampleBean("Test2", "ipso", "facto")
    );
    
    try (Writer writer  = new FileWriter(path.toString())) {

        StatefulBeanToCsv<CsvBean> sbc = new StatefulBeanToCsvBuilder<CsvBean>(writer)
          .withQuotechar('\'')
          .withSeparator(CSVWriter.DEFAULT_SEPARATOR)
          .build();

        sbc.write(sampleData);
    }
    return Helpers.readFile(path);
}

Here we’re specifying how we’ll delimit and quote our data, which is supplied as a List of specified CsvBean objects.

在这里,我们要指定如何给我们的数据定界和报价,这些数据是以指定的List CsvBean 对象的形式提供。

We can then call our method writeCsvFromBean() after passing in the desired output file path:

然后我们可以在传入所需的输出文件路径后调用我们的方法writeCsvFromBean()

public String writeCsvFromBeanExample() {
    Path path = Paths.get(
      ClassLoader.getSystemResource("csv/writtenBean.csv").toURI()); 
    return BeanExamples.writeCsvFromBean(path); 
}

4. Conclusion

4.结论

In this brief article, we discussed synchronous code examples for OpenCSV using beans, CSVReader, and CSVWriter. For more information, check out the official docs here.

在这篇简短的文章中,我们讨论了使用Bean、CSVReaderCSVWriterOpenCSV同步代码示例。更多信息,请查看官方文档这里。

As always, the code samples are provided over on GitHub.

一如既往,代码样本在GitHub上提供