Java 中读取 CSV 文件
简介
在数据处理和分析的场景中,CSV(逗号分隔值)文件是一种常用的文件格式,用于存储表格数据。在 Java 中,读取 CSV 文件是一项常见的任务。本文将详细介绍在 Java 中读取 CSV 文件的基础概念、使用方法、常见实践以及最佳实践,帮助读者更好地处理 CSV 文件数据。
目录
- 基础概念
- 使用方法
- 使用
BufferedReader
和String.split()
- 使用 OpenCSV 库
- 使用 Apache Commons CSV 库
- 使用
- 常见实践
- 处理表头
- 处理缺失值
- 处理不同分隔符
- 最佳实践
- 性能优化
- 错误处理
- 小结
- 参考资料
基础概念
CSV 文件是一种纯文本文件,其中的数据以逗号分隔,每行代表一条记录。文件的第一行通常是表头,用于描述每列的数据含义。例如:
姓名,年龄,城市
张三,25,北京
李四,30,上海
在 Java 中读取 CSV 文件,我们需要将文件内容解析成合适的数据结构,例如 List<List<String>>
,其中外层 List
代表每一行,内层 List
代表每一行中的每一列数据。
使用方法
使用 BufferedReader
和 String.split()
这是一种最基本的读取 CSV 文件的方法,使用 Java 标准库中的 BufferedReader
逐行读取文件内容,然后使用 String.split()
方法按逗号分隔每行数据。
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class CSVReaderBasic {
public static void main(String[] args) {
String csvFilePath = "data.csv";
List<List<String>> data = new ArrayList<>();
try (BufferedReader br = new BufferedReader(new FileReader(csvFilePath))) {
String line;
while ((line = br.readLine()) != null) {
String[] values = line.split(",");
List<String> row = new ArrayList<>();
for (String value : values) {
row.add(value);
}
data.add(row);
}
} catch (IOException e) {
e.printStackTrace();
}
for (List<String> row : data) {
System.out.println(row);
}
}
}
使用 OpenCSV 库
OpenCSV 是一个专门用于处理 CSV 文件的库,它提供了更方便的 API 来读取和写入 CSV 文件。
首先,在 pom.xml
中添加依赖:
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>5.7.1</version>
</dependency>
然后,使用 OpenCSV 读取 CSV 文件:
import com.opencsv.CSVReader;
import com.opencsv.exceptions.CsvException;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;
public class OpenCSVExample {
public static void main(String[] args) {
String csvFilePath = "data.csv";
try (CSVReader reader = new CSVReader(new FileReader(csvFilePath))) {
List<String[]> lines = reader.readAll();
for (String[] line : lines) {
for (String value : line) {
System.out.print(value + " ");
}
System.out.println();
}
} catch (IOException | CsvException e) {
e.printStackTrace();
}
}
}
使用 Apache Commons CSV 库
Apache Commons CSV 也是一个强大的 CSV 处理库,提供了丰富的功能。
在 pom.xml
中添加依赖:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>1.9.0</version>
</dependency>
读取 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;
public class ApacheCommonsCSVExample {
public static void main(String[] args) {
String csvFilePath = "data.csv";
try (FileReader fileReader = new FileReader(csvFilePath);
CSVParser csvParser = new CSVParser(fileReader, CSVFormat.DEFAULT)) {
for (CSVRecord csvRecord : csvParser) {
for (String value : csvRecord) {
System.out.print(value + " ");
}
System.out.println();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
常见实践
处理表头
通常,CSV 文件的第一行是表头。我们可以将表头单独处理,例如存储在一个 List
中。
使用 OpenCSV 处理表头:
import com.opencsv.CSVReader;
import com.opencsv.exceptions.CsvException;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;
public class HeaderHandling {
public static void main(String[] args) {
String csvFilePath = "data.csv";
try (CSVReader reader = new CSVReader(new FileReader(csvFilePath))) {
List<String[]> lines = reader.readAll();
if (!lines.isEmpty()) {
String[] headers = lines.get(0);
List<String> headerList = new ArrayList<>();
for (String header : headers) {
headerList.add(header);
}
System.out.println("Headers: " + headerList);
for (int i = 1; i < lines.size(); i++) {
String[] row = lines.get(i);
for (String value : row) {
System.out.print(value + " ");
}
System.out.println();
}
}
} catch (IOException | CsvException e) {
e.printStackTrace();
}
}
}
处理缺失值
在 CSV 文件中,可能会存在缺失值。我们可以在读取数据时对缺失值进行处理,例如替换为默认值。
使用 Apache Commons 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;
public class MissingValueHandling {
public static void main(String[] args) {
String csvFilePath = "data.csv";
try (FileReader fileReader = new FileReader(csvFilePath);
CSVParser csvParser = new CSVParser(fileReader, CSVFormat.DEFAULT)) {
for (CSVRecord csvRecord : csvParser) {
for (String value : csvRecord) {
if (value.isEmpty()) {
System.out.print("N/A ");
} else {
System.out.print(value + " ");
}
}
System.out.println();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
处理不同分隔符
CSV 文件不一定使用逗号作为分隔符,可能使用分号、制表符等。我们可以通过相应库的 API 来指定分隔符。
使用 OpenCSV 处理分号分隔的 CSV 文件:
import com.opencsv.CSVReaderBuilder;
import com.opencsv.exceptions.CsvException;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;
public class DifferentDelimiter {
public static void main(String[] args) {
String csvFilePath = "data_semicolon.csv";
try (FileReader fileReader = new FileReader(csvFilePath);
com.opencsv.CSVReader reader = new CSVReaderBuilder(fileReader)
.withSeparator(';')
.build()) {
List<String[]> lines = reader.readAll();
for (String[] line : lines) {
for (String value : line) {
System.out.print(value + " ");
}
System.out.println();
}
} catch (IOException | CsvException e) {
e.printStackTrace();
}
}
}
最佳实践
性能优化
- 批量读取:使用库提供的批量读取方法,减少磁盘 I/O 次数。例如,OpenCSV 的
readAll()
方法一次性读取所有行。 - 使用缓冲区:在使用
BufferedReader
时,合理设置缓冲区大小,提高读取效率。
错误处理
- 异常捕获:在读取 CSV 文件时,要捕获可能的异常,如
IOException
、CsvException
等,并进行适当处理。 - 数据验证:在读取数据后,对数据进行验证,确保数据的准确性和完整性。
小结
本文介绍了在 Java 中读取 CSV 文件的多种方法,包括使用标准库的 BufferedReader
和 String.split()
,以及使用 OpenCSV 和 Apache Commons CSV 库。同时,还讨论了常见实践和最佳实践,如处理表头、缺失值、不同分隔符,以及性能优化和错误处理等。通过这些知识,读者可以根据具体需求选择合适的方法来高效处理 CSV 文件数据。