在 Java 中使用Apache Commons CSV 读取/写入 CSV 文件

x33g5p2x  于2021-10-17 转载在 Java  
字(6.8k)|赞(0)|评价(0)|浏览(2138)

读取或写入 CSV 文件是 Java 开发人员在日常工作中遇到的一个非常常见的用例。

如果您需要一种简单的方法来读取 CSV 文件或为您的项目生成一个新文件,那么这篇博文适合您。

在这篇文章中,您将学习如何使用名为 Apache Commons CSV 的非常简单的开源库在 Java 中读取和写入 CSV 文件。

添加 Apache Commons CSV 依赖项

首先,您需要在项目中添加 apache-commons-csv 依赖项。如果您使用 maven,则将以下依赖项添加到您的 pom.xml 文件中 -

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-csv</artifactId>
    <version>1.5</version>
</dependency>

如果 您选择Gradle构建系统,则将以下内容添加到您的 build.gradle 文件中 -

compile "org.apache.commons:commons-csv:1.5"

CSV 文件示例

以下是我们将在示例中读取和解析的示例 CSV 文件。它包含应用程序的用户名、电子邮件、电话号码和国家/地区。我们称之为 users.csv

Rajeev Kumar Singh ♥,rajeevs@example.com,+91-9999999999,India
Sachin Tendulkar,sachin@example.com,+91-9999999998,India
Barak Obama,barak.obama@example.com,+1-1111111111,United States
Donald Trump,donald.trump@example.com,+1-2222222222,United States

CSV 文件带有标题的示例

使用没有标题的 CSV 文件通常不是一个好主意。以下是另一个包含标题的示例 CSV 文件。我们称之为 users-with-header.csv

Name,Email,Phone,Country
Rajeev Kumar Singh ♥,rajeevs@example.com,+91-9999999999,India
Sachin Tendulkar,sachin@example.com,+91-9999999998,India
Barak Obama,barak.obama@example.com,+1-1111111111,United States
Donald Trump,donald.trump@example.com,+1-2222222222,United States

在本文中,我将解释如何使用 Apache Commons CSV 读取和解析带有标头和不带标头的 CSV 文件。

前两个示例显示如何读取没有标题的 CSV 文件,第三个示例显示如何读取带标题的 CSV 文件。

读取 CSV 文件(按列索引访问值)

下面的示例显示了如何使用 Apache Commons CSV 读取和解析上述示例 CSV 文件 users.csv -

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import java.io.IOException;
import java.io.Reader;
import java.nio.file.Files;
import java.nio.file.Paths;

public class BasicCSVReader {
    private static final String SAMPLE_CSV_FILE_PATH = "./users.csv";

    public static void main(String[] args) throws IOException {
        try (
            Reader reader = Files.newBufferedReader(Paths.get(SAMPLE_CSV_FILE_PATH));
            CSVParser csvParser = new CSVParser(reader, CSVFormat.DEFAULT);
        ) {
            for (CSVRecord csvRecord : csvParser) {
                // Accessing Values by Column Index
                String name = csvRecord.get(0);
                String email = csvRecord.get(1);
                String phone = csvRecord.get(2);
                String country = csvRecord.get(3);

                System.out.println("Record No - " + csvRecord.getRecordNumber());
                System.out.println("---------------");
                System.out.println("Name : " + name);
                System.out.println("Email : " + email);
                System.out.println("Phone : " + phone);
                System.out.println("Country : " + country);
                System.out.println("---------------\n\n");
            }
        }
    }
}

够简单!我们为示例文件创建了一个 BufferedReader,并使用默认的 CSV 格式将其传递给 CSVParser。一旦我们有了 CSVParser,我们就可以使用 for 循环一一遍历所有记录。

在上面的示例中,我们一次从 CSV 文件中解析并读取一条记录。 CSVParser 类还提供了一个名为 getRecords() 的方法来一次性将所有记录读入内存——

// Reading all records at once into memory
List<CSVRecord> csvRecords = csvParser.getRecords();

但是,如果您正在阅读非常大的 CSV 文件,则应避免使用此方法。您可能会遇到内存问题,因为 getRecords() 方法将整个 CSV 内容加载到内存中。

读取 CSV 文件(按分配给每列的名称访问值)

在前面的示例中,我们使用它们的列索引访问了每条记录中的值。如果您不想使用列索引来检索每条记录中的值,那么您可以为 CSV 文件中的每一列分配名称,并使用分配的名称检索值。

查看以下示例,其中我们定义了一个手动标头并使用标头名称检索值。

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.nio.file.Files;
import java.nio.file.Paths;

public class CSVReaderWithManualHeader {
    private static final String SAMPLE_CSV_FILE_PATH = "./users.csv";

    public static void main(String[] args) throws IOException {
        try (
            Reader reader = Files.newBufferedReader(Paths.get(SAMPLE_CSV_FILE_PATH));
            CSVParser csvParser = new CSVParser(reader, CSVFormat.DEFAULT
                    .withHeader("Name", "Email", "Phone", "Country")
                    .withIgnoreHeaderCase()
                    .withTrim());
        ) {
            for (CSVRecord csvRecord : csvParser) {
                // Accessing values by the names assigned to each column
                String name = csvRecord.get("Name");
                String email = csvRecord.get("Email");
                String phone = csvRecord.get("Phone");
                String country = csvRecord.get("Country");

                System.out.println("Record No - " + csvRecord.getRecordNumber());
                System.out.println("---------------");
                System.out.println("Name : " + name);
                System.out.println("Email : " + email);
                System.out.println("Phone : " + phone);
                System.out.println("Country : " + country);
                System.out.println("---------------\n\n");
            }
        }
    }
}

请注意,我们还指定了一些附加设置,例如 withIgnoreHeaderCase()withTrim()CSVFormat

ignoreHeaderCase 设置用于使标题名称不区分大小写,trim 设置从列值中修剪前导和尾随空格。

读取带有标题自动检测功能的 CSV 文件(按标题名称访问值)

在此示例中,我们将读取包含标题 users-with-header.csv 的示例 CSV 文件。

使用 Apache Commons CSV 读取此类 CSV 文件非常容易。您只需要添加一个名为 withFirstRecordAsHeader() 的设置。

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.nio.file.Files;
import java.nio.file.Paths;

public class CSVReaderWithHeaderAutoDetection {
    private static final String SAMPLE_CSV_FILE_PATH = "./users-with-header.csv";

    public static void main(String[] args) throws IOException {
        try (
            Reader reader = Files.newBufferedReader(Paths.get(SAMPLE_CSV_FILE_PATH));
            CSVParser csvParser = new CSVParser(reader, CSVFormat.DEFAULT
                    .withFirstRecordAsHeader()
                    .withIgnoreHeaderCase()
                    .withTrim());
        ) {
            for (CSVRecord csvRecord : csvParser) {
                // Accessing values by Header names
                String name = csvRecord.get("Name");
                String email = csvRecord.get("Email");
                String phone = csvRecord.get("Phone");
                String country = csvRecord.get("Country");

                System.out.println("Record No - " + csvRecord.getRecordNumber());
                System.out.println("---------------");
                System.out.println("Name : " + name);
                System.out.println("Email : " + email);
                System.out.println("Phone : " + phone);
                System.out.println("Country : " + country);
                System.out.println("---------------\n\n");
            }
        }
    }

}

Apache Commons CSV 使用第一条记录作为标题记录,并允许您使用标题名称检索值。

生成 CSV 文件

最后,让我们看一个使用 Apache Commons CSV 生成 CSV 文件的示例。

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;

public class CSVWriter {
    private static final String SAMPLE_CSV_FILE = "./sample.csv";

    public static void main(String[] args) throws IOException {
        try (
            BufferedWriter writer = Files.newBufferedWriter(Paths.get(SAMPLE_CSV_FILE));

            CSVPrinter csvPrinter = new CSVPrinter(writer, CSVFormat.DEFAULT
                    .withHeader("ID", "Name", "Designation", "Company"));
        ) {
            csvPrinter.printRecord("1", "Sundar Pichai ♥", "CEO", "Google");
            csvPrinter.printRecord("2", "Satya Nadella", "CEO", "Microsoft");
            csvPrinter.printRecord("3", "Tim cook", "CEO", "Apple");

            csvPrinter.printRecord(Arrays.asList("4", "Mark Zuckerberg", "CEO", "Facebook"));

            csvPrinter.flush();            
        }
    }
}

上述程序将生成以下 CSV 文件 -

ID,Name,Designation,Company
1,Sundar Pichai ♥,CEO,Google
2,Satya Nadella,CEO,Microsoft
3,Tim cook,CEO,Apple
4,Mark Zuckerberg,CEO,Facebook

结论

这就是所有的人。在本文中,我们学习了如何使用 Apache Commons CSV 库在 Java 中读写 CSV 文件。

您可以在 my github repository 中找到本文中提供的所有代码示例。

相关文章