OpenCSV简介

2025/03/28

1. 简介

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

2. 设置

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

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

你可以在官方网站或通过Maven仓库快速搜索找到OpenCSV的.jar。

我们的.csv文件非常简单;我们将其保留为两列四行:

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

3. Bean或者非Bean

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

  1. 使用方便的CSVReader和CSVWriter对象(用于更简单的操作)
  2. 使用CsvToBean将.csv文件转换为Bean(以带注解的POJO形式实现)

在本文中,我们将坚持使用同步(或阻塞)示例,以便我们能够专注于基础知识。

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

我们将在后续文章中深入探讨OpenCSV的异步示例。

3.1 CSVReader

让我们通过提供的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();
        }
    }
}

然后我们可以通过传入文件路径来调用该方法:

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

类似地,我们可以抽象出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;
}

最后,我们可以通过传入文件路径来调用该方法:

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

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

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

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

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

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

与往常一样,我们需要记得关闭所有读取器以防止内存泄漏。

3.2 CSVWriter

CSVWriter类似地提供一次性或逐行写入.csv文件的功能。

让我们看看如何逐行写入.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(line);
        }
        return Helpers.readFile(path);
    }
}

然后我们指定要保存文件的位置,并调用刚刚编写的方法:

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

我们还可以通过传入代表.csv行的字符串数组列表来一次性写入.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);
}

最后,我们这样调用它:

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

3.3 基于Bean的读取

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

这是一个简单的Bean,我们可以使用它来序列化我们之前的两列.csv:

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

    @CsvBindByPosition(position = 1)
    private String exampleColTwo;

    // getters and setters
}

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

首先,我们将创建一个名为CsvBean的超类,它将允许我们重用和概括下面构建的方法:

public class CsvBean { }

这是一个子类的示例:

public class NamedColumnBean extends CsvBean {

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

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

    // getters and setters
}

接下来,我们将使用CsvToBean抽象一个同步返回的列表:

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();
}

然后传入我们的Bean(clazz),这样做是为了将Bean的字段与.csv行的相应列关联起来。

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

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

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

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的写入

最后我们来看看如何使用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);
}

这里我们指定如何界定和引用我们的数据,它以指定CsvBean对象的列表的形式提供。

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

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

4. 总结

在这篇简短的文章中,我们讨论了使用Bean、CSVReader和CSVWriter的OpenCSV同步代码示例。有关更多信息,请查看此处的官方文档

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章