跳转至

Java 中处理 CSV 文件

简介

CSV(Comma-Separated Values),即逗号分隔值,是一种常见的文本文件格式,用于存储表格数据。每行数据代表表格中的一行记录,字段之间通常用逗号分隔。在 Java 开发中,处理 CSV 文件是一项常见任务,无论是数据导入、导出,还是数据处理和分析。本文将深入探讨在 Java 中处理 CSV 文件的基础概念、使用方法、常见实践以及最佳实践。

目录

  1. 基础概念
  2. 使用方法
    • 使用标准库(BufferedReader 和 BufferedWriter)
    • 使用 OpenCSV 库
    • 使用 Apache Commons CSV
  3. 常见实践
    • 读取 CSV 文件
    • 写入 CSV 文件
    • 处理带引号的字段
    • 处理不同分隔符
  4. 最佳实践
    • 性能优化
    • 错误处理
    • 数据验证
  5. 小结
  6. 参考资料

基础概念

CSV 文件以纯文本形式存储数据,每行数据代表一条记录,字段之间用特定的分隔符(通常是逗号)分隔。例如:

Name,Age,City
John Doe,30,New York
Jane Smith,25,Los Angeles

在处理 CSV 文件时,需要注意以下几点: - 分隔符:除了逗号,还可以使用其他字符作为分隔符,如制表符(\t)、分号(;)等。 - 引号:为了包含可能包含分隔符或换行符的字段,可以使用引号(通常是双引号)将字段括起来。例如:"This is a "quoted" field", 123

使用方法

使用标准库(BufferedReader 和 BufferedWriter)

Java 的标准库提供了 BufferedReaderBufferedWriter 类,可以用于读取和写入 CSV 文件。

读取 CSV 文件

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class CSVReaderExample {
    public static void main(String[] args) {
        String csvFilePath = "data.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();
        }
    }
}

写入 CSV 文件

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class CSVWriterExample {
    public static void main(String[] args) {
        String csvFilePath = "output.csv";
        String[] headers = {"Name", "Age", "City"};
        String[] data = {"John Doe", "30", "New York"};

        try (BufferedWriter bw = new BufferedWriter(new FileWriter(csvFilePath))) {
            // 写入表头
            for (int i = 0; i < headers.length; i++) {
                bw.write(headers[i]);
                if (i < headers.length - 1) {
                    bw.write(",");
                }
            }
            bw.newLine();

            // 写入数据
            for (int i = 0; i < data.length; i++) {
                bw.write(data[i]);
                if (i < data.length - 1) {
                    bw.write(",");
                }
            }
            bw.newLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

使用 OpenCSV 库

OpenCSV 是一个流行的 Java 库,用于处理 CSV 文件,它提供了更方便的 API。

引入依赖

如果使用 Maven,可以在 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 OpenCSVReaderExample {
    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 + "\t");
                }
                System.out.println();
            }
        } catch (IOException | CsvException e) {
            e.printStackTrace();
        }
    }
}

写入 CSV 文件

import com.opencsv.CSVWriter;

import java.io.FileWriter;
import java.io.IOException;

public class OpenCSVWriterExample {
    public static void main(String[] args) {
        String csvFilePath = "output.csv";
        String[] headers = {"Name", "Age", "City"};
        String[] data = {"John Doe", "30", "New York"};

        try (CSVWriter writer = new CSVWriter(new FileWriter(csvFilePath))) {
            writer.writeNext(headers);
            writer.writeNext(data);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

使用 Apache Commons CSV

Apache Commons CSV 是 Apache Commons 项目的一部分,提供了丰富的功能来处理 CSV 文件。

引入依赖

如果使用 Maven,可以在 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 ApacheCommonsCSVReaderExample {
    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 + "\t");
                }
                System.out.println();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

写入 CSV 文件

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;

import java.io.FileWriter;
import java.io.IOException;

public class ApacheCommonsCSVWriterExample {
    public static void main(String[] args) {
        String csvFilePath = "output.csv";
        String[] headers = {"Name", "Age", "City"};
        String[] data = {"John Doe", "30", "New York"};

        try (FileWriter fileWriter = new FileWriter(csvFilePath);
             CSVPrinter csvPrinter = new CSVPrinter(fileWriter, CSVFormat.DEFAULT
                   .withHeader(headers))) {
            csvPrinter.printRecord(data);
            csvPrinter.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

常见实践

读取 CSV 文件

读取 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 QuotedCSVReaderExample {
    public static void main(String[] args) {
        String csvFilePath = "quoted_data.csv";
        try (CSVReader reader = new CSVReaderBuilder(new FileReader(csvFilePath))
              .withQuoteChar('"')
              .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();
        }
    }
}

写入 CSV 文件

写入 CSV 文件时,需要确保数据格式正确,并且正确处理表头和换行符。例如,使用 Apache Commons CSV 写入带表头的 CSV 文件:

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;

import java.io.FileWriter;
import java.io.IOException;

public class HeaderCSVWriterExample {
    public static void main(String[] args) {
        String csvFilePath = "output_with_header.csv";
        String[] headers = {"Name", "Age", "City"};
        String[] data = {"John Doe", "30", "New York"};

        try (FileWriter fileWriter = new FileWriter(csvFilePath);
             CSVPrinter csvPrinter = new CSVPrinter(fileWriter, CSVFormat.DEFAULT
                   .withHeader(headers))) {
            csvPrinter.printRecord(data);
            csvPrinter.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

处理带引号的字段

在处理带引号的字段时,需要确保正确解析和写入这些字段。不同的库提供了相应的配置选项来处理引号。例如,使用 OpenCSV 库处理带引号的字段:

import com.opencsv.CSVReader;
import com.opencsv.CSVWriter;
import com.opencsv.exceptions.CsvException;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;

public class QuotedFieldsExample {
    public static void main(String[] args) {
        String inputFilePath = "quoted_input.csv";
        String outputFilePath = "quoted_output.csv";

        try (CSVReader reader = new CSVReaderBuilder(new FileReader(inputFilePath))
              .withQuoteChar('"')
              .build();
             CSVWriter writer = new CSVWriterBuilder(new FileWriter(outputFilePath))
              .withQuoteChar('"')
              .build()) {
            List<String[]> lines = reader.readAll();
            for (String[] line : lines) {
                writer.writeNext(line);
            }
        } catch (IOException | CsvException e) {
            e.printStackTrace();
        }
    }
}

处理不同分隔符

如果 CSV 文件使用的分隔符不是逗号,可以通过配置相应的库来处理。例如,使用 Apache Commons CSV 处理以分号为分隔符的 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 SemicolonCSVReaderExample {
    public static void main(String[] args) {
        String csvFilePath = "semicolon_data.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();
        }
    }
}

最佳实践

性能优化

  • 批量读取和写入:避免逐行读取和写入,尽量批量处理数据,以减少 I/O 操作。
  • 使用缓冲区:使用缓冲流(如 BufferedReaderBufferedWriter)来提高读写性能。
  • 选择合适的库:不同的库在性能上可能有所差异,根据具体需求选择性能最优的库。

错误处理

  • 捕获异常:在读取和写入 CSV 文件时,要捕获并处理可能的 IOException 和其他相关异常。
  • 日志记录:记录详细的错误信息,以便于调试和排查问题。

数据验证

  • 字段类型验证:在读取 CSV 文件时,验证字段的类型是否符合预期。
  • 数据完整性验证:确保数据的完整性,例如检查必填字段是否为空。

小结

在 Java 中处理 CSV 文件有多种方法,从使用标准库到借助第三方库。每种方法都有其优缺点,开发者应根据具体需求选择合适的方式。通过遵循最佳实践,可以提高代码的性能、可靠性和可维护性。希望本文能帮助读者深入理解并高效使用 CSV 在 Java 中的处理。

参考资料