1. 引言

在Java开发中,从文件读取数据是常见需求。当处理CSV这类结构化数据时,将其加载到二维数组能极大提升操作效率。本文将探讨三种主流实现方案:传统BufferedReader、Java 8 NIO流式API以及Apache Commons CSV库,并对比它们在实际场景中的优劣。

2. 问题场景

假设我们需要将如下CSV文件内容转换为二维数组:

value1,value2,value3
value4,value5,value6
value7,value8,value9

目标数据结构应为:

String[][] expectedData = {
    {"value1", "value2", "value3"},
    {"value4", "value5", "value6"},
    {"value7", "value8", "value9"}
};

核心挑战在于:如何高效完成转换的同时,确保代码对大型数据集的兼容性和可维护性。

3. 使用 BufferedReader

这是最基础的实现方式,通过逐行读取和字符串分割完成转换:

try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
    List<String[]> dataList = new ArrayList<>();
    String line;
    while ((line = br.readLine()) != null) {
        dataList.add(line.split(","));
    }
    return dataList.toArray(new String[0][]);
}

关键点解析:

  1. ✅ 使用try-with-resources自动关闭资源,避免内存泄漏
  2. ✅ 动态数组ArrayList处理不确定行数
  3. ⚠️ split()方法对复杂CSV格式(如含引号字段)支持有限

单元测试验证:

@Test
public void givenFile_whenUsingBufferedReader_thenArrayIsCorrect() throws IOException {
    String[][] actualData = readFileTo2DArrayUsingBufferedReader("src/test/resources/test_file.txt");
    assertArrayEquals(expectedData, actualData);
}

4. 使用 Java NIO Files API

Java 8引入的NIO API提供了更简洁的流式处理方案:

List<String> lines = Files.readAllLines(Paths.get(filePath));
return lines.stream()
        .map(line -> line.split(","))
        .toArray(String[][]::new);

优势对比:

  • ✅ 代码行数减少40%
  • ✅ 函数式编程风格更易读
  • ⚠️ readAllLines()会一次性加载整个文件,超大文件需谨慎

测试用例:

@Test
public void givenFile_whenUsingStreamAPI_thenArrayIsCorrect() throws IOException {
    String[][] actualData = readFileTo2DArrayUsingStreamAPI("src/test/resources/test_file.txt");
    assertArrayEquals(expectedData, actualData);
}

提示:现代Java项目优先推荐此方案,除非处理GB级文件。

5. 使用 Apache Commons CSV

面对复杂CSV格式(含转义字符、自定义分隔符等),专业库更可靠:

Reader reader = new FileReader(filePath);
CSVParser csvParser = new CSVParser(reader, CSVFormat.DEFAULT);

List<String[]> dataList = new ArrayList<>();
for (CSVRecord record : csvParser) {
    String[] data = new String[record.size()];
    for (int i = 0; i < record.size(); i++) {
        data[i] = record.get(i);
    }
    dataList.add(data);
}
return dataList.toArray(new String[dataList.size()][]);

核心特性:

  • ✅ 自动处理引号包裹的字段(如"value,with,comma"
  • ✅ 支持自定义分隔符和转义规则
  • ✅ 内置数据校验机制

测试验证:

@Test
public void givenFile_whenUsingApacheCommonsCSV_thenArrayIsCorrect() throws IOException {
    String[][] actualData = readFileTo2DArrayUsingApacheCommonsCSV("src/test/resources/test_file.csv");
    assertArrayEquals(expectedData, actualData);
}

踩坑提醒:需添加Maven依赖:

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

6. 方案对比总结

实现方式 适用场景 优势 局限性
BufferedReader 简单CSV/小文件 无需外部依赖 复杂格式支持差
Java NIO Files 中小型文件/现代Java项目 代码简洁/函数式风格 大文件内存占用高
Apache Commons CSV 企业级CSV/复杂格式 格式兼容性强/功能完善 需引入第三方库

选择建议

  • 基础需求 → NIO Files API(简单粗暴)
  • 生产环境复杂CSV → Apache Commons CSV(专业可靠)
  • 遗留系统维护 → BufferedReader(兼容性好)

完整示例代码已托管至GitHub仓库,包含各方案完整实现及测试用例。


原始标题:Reading a File Into a 2d Array in Java | Baeldung