1. 概述

简单来说,CSV(Comma-Separated Values,逗号分隔值)文件是一种以逗号作为分隔符来组织数据的文本格式。

在本篇文章中,我们将介绍几种在 Java 中将 CSV 文件内容读取到数组的不同方法。

2. 示例 CSV 文件

我们使用一个简单的 CSV 文件 book.csv 作为示例:

Mary Kom,Unbreakable
Kapil Isapuari,Farishta

在 Java 程序中,通常我们会定义一个逗号分隔符用于将每一行拆分为独立的值

public static final String COMMA_DELIMITER = ",";

⚠️ 需要注意的是,并不存在一个通用的分隔符或正则表达式能够处理所有类型的 CSV 值。这不仅适用于包含逗号的字段,也适用于包含其他特殊字符的情况

如果已有的 CSV 文件中包含分隔符字符(比如逗号)作为值的一部分,而你又无法使用本文提到的方法,那么你需要更换分隔符字符或正则表达式。

在创建新的 CSV 文件时,应选择一个不会出现在任何字段中的字符作为分隔符。

3. 使用 java.io.BufferedReader

最基础的方式是使用 BufferedReaderreadLine() 方法逐行读取文件,然后根据逗号分隔符将每一行拆分为多个字段:

List<List<String>> records = new ArrayList<>();
try (BufferedReader br = new BufferedReader(new FileReader("book.csv"))) {
    String line;
    while ((line = br.readLine()) != null) {
        String[] values = line.split(COMMA_DELIMITER);
        records.add(Arrays.asList(values));
    }
}

✅ 简单粗暴,适合处理结构简单的 CSV 文件。

4. 使用 java.util.Scanner

另一种方式是使用 Scanner 类按行读取文件内容:

List<List<String>> records = new ArrayList<>();
try (Scanner scanner = new Scanner(new File("book.csv"))) {
    while (scanner.hasNextLine()) {
        records.add(getRecordFromLine(scanner.nextLine()));
    }
}

接着,我们将每一行解析为一个字符串列表:

private List<String> getRecordFromLine(String line) {
    List<String> values = new ArrayList<String>();
    try (Scanner rowScanner = new Scanner(line)) {
        rowScanner.useDelimiter(COMMA_DELIMITER);
        while (rowScanner.hasNext()) {
            values.add(rowScanner.next());
        }
    }
    return values;
}

这种方式逻辑清晰,适合喜欢封装逻辑的开发者。

5. 使用 Files 工具类

Java 7 引入了 java.nio.file.Files 工具类,提供了多种静态方法来处理文件。下面介绍几种基于 Files 的读取方式。

5.1. 使用 Files#lines

Java 8 中新增的 lines() 方法可以将文件内容作为 Stream 来处理,适合进行函数式编程风格的处理:

try (Stream<String> lines = Files.lines(Paths.get(CSV_FILE))) {
    List<List<String>> records = lines.map(line -> Arrays.asList(line.split(COMMA_DELIMITER)))
      .collect(Collectors.toList());
}

其中,Paths.get(CSV_FILE) 返回一个 Path 实例,代表文件路径。我们使用 map() 将每一行转换为字符串列表。

✅ 适合处理中等大小的文件,结合 Stream API 可读性更强。

5.2. 使用 Files#readAllLines

readAllLines() 方法会一次性将整个文件加载到内存中,返回每行内容组成的列表:

List<List<String>> records = Files.readAllLines(Paths.get(CSV_FILE))
  .stream()
  .map(line -> Arrays.asList(line.split(COMMA_DELIMITER)))
  .collect(Collectors.toList());

⚠️ 注意:该方法会将整个文件读入内存,不适合处理大文件

5.3. 使用 Files#newBufferedReader

该方法返回一个 BufferedReader 实例,适合处理大文件:

try (BufferedReader reader = Files.newBufferedReader(Paths.get(CSV_FILE))) {
    List<List<String>> records = reader.lines()
      .map(line -> Arrays.asList(line.split(COMMA_DELIMITER)))
      .collect(Collectors.toList());
}

✅ 推荐在处理大文件时使用此方式,效率更高。

6. 处理字段中包含逗号的情况

当 CSV 文件中的字段本身包含逗号时,使用简单的逗号分隔符会导致字段被错误拆分。例如:

"Kom, Mary",Unbreakable
"Isapuari, Kapil",Farishta

此时,直接使用 split(",") 会导致 "Kom, Mary" 被错误地拆分为 "KomMary"

6.1. 使用自定义 CSV 解析器

我们可以实现一个简单的解析器,使用 StringBuilder 和引号标记来处理带逗号的字段:

List<List<String>> records = new ArrayList<List<String>>();
try (BufferedReader br = new BufferedReader(new FileReader(CSV_FILE))) {
    String line = "";
    while ((line = br.readLine()) != null) {
        records.add(parseLine(line));
    }
}

解析方法如下:

private static List<String> parseLine(String line) {
    List values = new ArrayList<>();
    boolean inQuotes = false;
    StringBuilder currentValue = new StringBuilder();

    for (char c : line.toCharArray()) {
        if (c == '"') {
            inQuotes = !inQuotes;
        } else if (c == ',' && !inQuotes) {
            values.add(currentValue.toString());
            currentValue = new StringBuilder();
        } else {
            currentValue.append(c);
        }
    }
    values.add(currentValue.toString());
    return values;
}

✅ 适合需要处理复杂字段的场景,无需引入第三方库。

6.2. 使用其他分隔符

我们可以使用其他符号(如 |, /, ;)作为分隔符。例如:

"Kom, Mary"|Unbreakable
"Isapuari, Kapil"|Farishta

此时,我们只需要将分隔符改为:

public static final String COMMA_DELIMITER = "\\|";

⚠️ 注意在正则表达式中需要对特殊字符进行转义。

7. 使用 OpenCSV

OpenCSV 是一个强大的第三方库,专门用于处理 CSV 文件。它默认支持字段中包含逗号的情况:

List<List<String>> records = new ArrayList<List<String>>();
try (CSVReader csvReader = new CSVReader(new FileReader("book.csv"));) {
    String[] values = null;
    while ((values = csvReader.readNext()) != null) {
        records.add(Arrays.asList(values));
    }
}

✅ 对于复杂 CSV 文件,OpenCSV 是首选方案。支持字段引号、换行、转义等特性。

"Kom, Mary",Unbreakable
"Isapuari, Kapil",Farishta

更多关于 OpenCSV 的使用,请参考官方文档或我们的 OpenCSV 教程

8. 总结

本文介绍了多种将 CSV 文件读入 Java 数组的方式:

  • 基础方式:BufferedReader, Scanner
  • Java 7+ 工具类:Files.lines, Files.readAllLines, Files.newBufferedReader
  • 高级方式:自定义解析器、更换分隔符
  • 第三方库:OpenCSV

对于包含特殊字符的字段,建议使用 OpenCSV 或自定义解析器,以避免数据错误。


小结

  • 简单场景 → BufferedReader + split
  • 复杂场景 → OpenCSV 或自定义解析器
  • 大文件 → Files.newBufferedReader + Stream API

原始标题:Reading a CSV File into an Array | Baeldung

« 上一篇: Apache Storm 入门指南
» 下一篇: Scala 语言入门