如何在 Java 中读取 CSV 文件
简介
在数据处理和分析场景中,CSV(逗号分隔值)文件是一种常见的数据存储格式。它以纯文本形式存储表格数据,数据字段通过逗号分隔。在 Java 开发中,经常需要读取 CSV 文件来获取其中的数据并进行处理。本文将详细介绍在 Java 中读取 CSV 文件的基础概念、使用方法、常见实践以及最佳实践,帮助读者掌握这一重要的数据处理技能。
目录
- 基础概念
- 使用方法
- 使用 BufferedReader 读取
- 使用 OpenCSV 库读取
- 使用 Apache Commons CSV 库读取
- 常见实践
- 处理表头
- 处理不同分隔符
- 处理缺失值
- 最佳实践
- 错误处理
- 性能优化
- 内存管理
- 小结
- 参考资料
基础概念
CSV 文件是一种简单的文本文件格式,每行代表表格中的一行数据,字段之间用逗号(或其他指定的分隔符)分隔。例如,一个简单的 CSV 文件可能如下所示:
姓名,年龄,城市
张三,25,北京
李四,30,上海
在 Java 中读取 CSV 文件,就是将文件中的文本数据解析成 Java 可以处理的数据结构,例如数组、集合或自定义对象。
使用方法
使用 BufferedReader 读取
Java 的标准库提供了 BufferedReader
类来读取文本文件。我们可以使用它逐行读取 CSV 文件,并手动解析每行数据。
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class CSVReaderExample {
public static void main(String[] args) {
String csvFilePath = "path/to/your/file.csv";
try (BufferedReader br = new BufferedReader(new FileReader(csvFilePath))) {
String line;
while ((line = br.readLine())!= null) {
String[] values = line.split(",");
for (String value : values) {
System.out.print(value + "\t");
}
System.out.println();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
使用 OpenCSV 库读取
OpenCSV 是一个流行的 Java 库,用于处理 CSV 文件。它提供了更高级的 API,简化了 CSV 文件的读取操作。
首先,在 pom.xml
文件中添加依赖:
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>5.7.1</version>
</dependency>
然后,使用以下代码读取 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 = "path/to/your/file.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 + "\t");
}
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 = "path/to/your/file.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 + "\t");
}
System.out.println();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
常见实践
处理表头
很多 CSV 文件的第一行包含表头信息。我们可以通过以下方式跳过表头:
使用 OpenCSV:
import com.opencsv.CSVReader;
import com.opencsv.exceptions.CsvException;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;
public class OpenCSVHeaderExample {
public static void main(String[] args) {
String csvFilePath = "path/to/your/file.csv";
try (CSVReader reader = new CSVReader(new FileReader(csvFilePath))) {
List<String[]> lines = reader.readAll();
boolean isHeader = true;
for (String[] line : lines) {
if (isHeader) {
isHeader = false;
continue;
}
for (String value : line) {
System.out.print(value + "\t");
}
System.out.println();
}
} catch (IOException | CsvException e) {
e.printStackTrace();
}
}
}
使用 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 ApacheCommonsCSVHeaderExample {
public static void main(String[] args) {
String csvFilePath = "path/to/your/file.csv";
try (FileReader fileReader = new FileReader(csvFilePath);
CSVParser csvParser = new CSVParser(fileReader, CSVFormat.DEFAULT.withFirstRecordAsHeader())) {
for (CSVRecord csvRecord : csvParser.getRecords()) {
for (String value : csvRecord) {
System.out.print(value + "\t");
}
System.out.println();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
处理不同分隔符
有些 CSV 文件可能使用其他字符作为分隔符,例如分号。可以通过配置库的分隔符来处理这种情况。
使用 OpenCSV:
import com.opencsv.CSVReader;
import com.opencsv.CSVReaderBuilder;
import com.opencsv.exceptions.CsvException;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;
public class OpenCSVDelimiterExample {
public static void main(String[] args) {
String csvFilePath = "path/to/your/file.csv";
try (CSVReader reader = new CSVReaderBuilder(new FileReader(csvFilePath))
.withSeparator(';')
.build()) {
List<String[]> lines = reader.readAll();
for (String[] line : lines) {
for (String value : line) {
System.out.print(value + "\t");
}
System.out.println();
}
} catch (IOException | CsvException e) {
e.printStackTrace();
}
}
}
使用 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 ApacheCommonsCSVDelimiterExample {
public static void main(String[] args) {
String csvFilePath = "path/to/your/file.csv";
try (FileReader fileReader = new FileReader(csvFilePath);
CSVParser csvParser = new CSVParser(fileReader, CSVFormat.DEFAULT.withDelimiter(';'))) {
for (CSVRecord csvRecord : csvParser) {
for (String value : csvRecord) {
System.out.print(value + "\t");
}
System.out.println();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
处理缺失值
CSV 文件中可能存在缺失值。可以在读取时进行相应的处理,例如设置默认值。
使用 OpenCSV:
import com.opencsv.CSVReader;
import com.opencsv.exceptions.CsvException;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;
public class OpenCSVMissingValueExample {
public static void main(String[] args) {
String csvFilePath = "path/to/your/file.csv";
try (CSVReader reader = new CSVReader(new FileReader(csvFilePath))) {
List<String[]> lines = reader.readAll();
for (String[] line : lines) {
for (int i = 0; i < line.length; i++) {
if (line[i] == null || line[i].isEmpty()) {
line[i] = "N/A";
}
System.out.print(line[i] + "\t");
}
System.out.println();
}
} catch (IOException | CsvException e) {
e.printStackTrace();
}
}
}
使用 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 ApacheCommonsCSVMissingValueExample {
public static void main(String[] args) {
String csvFilePath = "path/to/your/file.csv";
try (FileReader fileReader = new FileReader(csvFilePath);
CSVParser csvParser = new CSVParser(fileReader, CSVFormat.DEFAULT)) {
for (CSVRecord csvRecord : csvParser) {
for (String value : csvRecord) {
if (value == null || value.isEmpty()) {
value = "N/A";
}
System.out.print(value + "\t");
}
System.out.println();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
最佳实践
错误处理
在读取 CSV 文件时,应进行全面的错误处理。例如,处理文件不存在、格式错误等异常情况。
import com.opencsv.CSVReader;
import com.opencsv.exceptions.CsvException;
import java.io.FileReader;
import java.io.IOException;
public class OpenCSVErrorHandlingExample {
public static void main(String[] args) {
String csvFilePath = "path/to/your/file.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 + "\t");
}
System.out.println();
}
} catch (IOException e) {
System.err.println("文件读取错误: " + e.getMessage());
} catch (CsvException e) {
System.err.println("CSV 解析错误: " + e.getMessage());
}
}
}
性能优化
对于大型 CSV 文件,性能优化很重要。可以使用流处理来减少内存占用,例如在 Apache Commons CSV 中使用 CSVParser
的流操作:
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 ApacheCommonsCSVPerformanceExample {
public static void main(String[] args) {
String csvFilePath = "path/to/your/file.csv";
try (FileReader fileReader = new FileReader(csvFilePath);
CSVParser csvParser = new CSVParser(fileReader, CSVFormat.DEFAULT)) {
csvParser.getRecords().stream()
.forEach(csvRecord -> {
for (String value : csvRecord) {
System.out.print(value + "\t");
}
System.out.println();
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
内存管理
避免一次性将整个 CSV 文件读入内存。如果数据量很大,可以逐行处理,减少内存压力。
小结
本文详细介绍了在 Java 中读取 CSV 文件的多种方法,包括使用标准库的 BufferedReader
,以及流行的第三方库 OpenCSV 和 Apache Commons CSV。同时,阐述了常见实践,如处理表头、不同分隔符和缺失值,还提供了最佳实践建议,涵盖错误处理、性能优化和内存管理。通过这些内容,读者可以根据具体需求选择合适的方法来高效处理 CSV 文件。