跳转至

Java 中读取 CSV 文件

简介

在数据处理和分析的场景中,CSV(逗号分隔值)文件是一种常用的文件格式,用于存储表格数据。在 Java 中,读取 CSV 文件是一项常见的任务。本文将详细介绍在 Java 中读取 CSV 文件的基础概念、使用方法、常见实践以及最佳实践,帮助读者更好地处理 CSV 文件数据。

目录

  1. 基础概念
  2. 使用方法
    • 使用 BufferedReaderString.split()
    • 使用 OpenCSV 库
    • 使用 Apache Commons CSV 库
  3. 常见实践
    • 处理表头
    • 处理缺失值
    • 处理不同分隔符
  4. 最佳实践
    • 性能优化
    • 错误处理
  5. 小结
  6. 参考资料

基础概念

CSV 文件是一种纯文本文件,其中的数据以逗号分隔,每行代表一条记录。文件的第一行通常是表头,用于描述每列的数据含义。例如:

姓名,年龄,城市
张三,25,北京
李四,30,上海

在 Java 中读取 CSV 文件,我们需要将文件内容解析成合适的数据结构,例如 List<List<String>>,其中外层 List 代表每一行,内层 List 代表每一行中的每一列数据。

使用方法

使用 BufferedReaderString.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 文件时,要捕获可能的异常,如 IOExceptionCsvException 等,并进行适当处理。
  • 数据验证:在读取数据后,对数据进行验证,确保数据的准确性和完整性。

小结

本文介绍了在 Java 中读取 CSV 文件的多种方法,包括使用标准库的 BufferedReaderString.split(),以及使用 OpenCSV 和 Apache Commons CSV 库。同时,还讨论了常见实践和最佳实践,如处理表头、缺失值、不同分隔符,以及性能优化和错误处理等。通过这些知识,读者可以根据具体需求选择合适的方法来高效处理 CSV 文件数据。

参考资料