Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Java

Đọc/ghi file CSV trong Java với OpenCSV

OpenCSV là thư viện phổ biến, dễ dùng để parse/ghi CSV trong Java. Xử lý tự động quote, escape, delimiter, header mapping.

Dependency (Maven/Gradle)



    com.opencsv
    opencsv
    5.8



implementation 'com.opencsv:opencsv:5.8'

1. Đọc CSV dòng per dòng (Streaming, tiết kiệm memory)

import com.opencsv.CSVReader;
import com.opencsv.exceptions.CsvException;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;

public class CsvReadDemo {
    public static void readLineByLine(String filePath) {
        try (CSVReader reader = new CSVReader(new FileReader(filePath))) {
            String[] line;
            int lineNum = 0;
            while ((line = reader.readNext()) != null) {
                lineNum++;
                if (lineNum == 1) {
                    System.out.println("Header: " + String.join(" | ", line));
                    continue;
                }
                System.out.printf("Row %d: %s%n", lineNum, String.join(" | ", line));
            }
        } catch (IOException | CsvException e) {
            e.printStackTrace();
        }
    }
    
    // Đọc tất cả vào List (chỉ file nhỏ)
    public static List readAll(String filePath) {
        try (CSVReader reader = new CSVReader(new FileReader(filePath))) {
            return reader.readAll();
        } catch (IOException | CsvException e) {
            throw new RuntimeException(e);
        }
    }
}

2. Đọc CSV mapping trực tiếp vào Bean (POJO) – Khuyên dùng

import com.opencsv.bean.CsvToBeanBuilder;
import com.opencsv.bean.HeaderColumnNameMappingStrategy;
import java.io.FileReader;
import java.util.List;

// POJO với annotation mapping
public class Employee {
    @CsvBindByName(column = "id")
    private int id;
    @CsvBindByName(column = "name")
    private String name;
    @CsvBindByName(column = "department")
    private String department;
    @CsvBindByName(column = "salary")
    private double salary;
    // getters, setters, toString
}

// Đọc
public class CsvBeanDemo {
    public static List readEmployees(String filePath) {
        try (FileReader reader = new FileReader(filePath)) {
            return new CsvToBeanBuilder(reader)
                .withType(Employee.class)
                .withIgnoreLeadingWhiteSpace(true)
                .withThrowExceptions(false)
                .build()
                .parse();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

3. Ghi CSV từ Bean

import com.opencsv.bean.StatefulBeanToCsv;
import com.opencsv.bean.StatefulBeanToCsvBuilder;
import com.opencsv.exceptions.CsvDataTypeMismatchException;
import com.opencsv.exceptions.CsvRequiredFieldEmptyException;
import java.io.FileWriter;
import java.util.List;

public class CsvWriteDemo {
    public static void writeEmployees(List employees, String filePath) {
        try (FileWriter writer = new FileWriter(filePath)) {
            StatefulBeanToCsv beanToCsv = new StatefulBeanToCsvBuilder(writer)
                .withQuotechar(CSVWriter.NO_QUOTE_CHARACTER)
                .withSeparator(CSVWriter.DEFAULT_SEPARATOR)
                .withOrderedResults(true)
                .build();
            beanToCsv.write(employees);
        } catch (IOException | CsvDataTypeMismatchException | CsvRequiredFieldEmptyException e) {
            throw new RuntimeException(e);
        }
    }
}

4. Cấu hình nâng cao

CSVReader reader = new CSVReaderBuilder(new FileReader(file))
    .withSkipLines(1)                    // Bỏ qua N dòng đầu
    .withCSVParser(new CSVParserBuilder()
        .withSeparator(';')              // Delimiter tùy chỉnh (mặc định ',')
        .withQuoteChar('"')
        .withEscapeChar('\\')
        .build())
    .build();

CSVWriter writer = new CSVWriter(new FileWriter(file),
    CSVWriter.DEFAULT_SEPARATOR,
    CSVWriter.NO_QUOTE_CHARACTER,       // Không quote
    CSVWriter.DEFAULT_ESCAPE_CHARACTER,
    CSVWriter.DEFAULT_LINE_END);

5. Xử lý file lớn (Streaming + Parallel)

// Java 8+ Stream từ CSVReader (OpenCSV 5.2+)
try (CSVReader reader = new CSVReader(new FileReader(largeFile))) {
    reader.stream() // Stream
         .skip(1)   // Bỏ header
         .parallel() // Xử lý song song
         .forEach(row -> processRow(row));
}

Lưu ý & Best Practices

  • Luôn dùng try-with-resources để tự đóng reader/writer.
  • File lớn: đọc dòng per dòng (streaming), KHÔNG readAll().
  • Encoding: Mặc định platform encoding. Chỉ định: new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8).
  • Header mapping: Dùng @CsvBindByName (header name) hoặc @CsvBindByPosition (index).
  • Type conversion: OpenCV tự convert String → primitive/wrapper. Custom converter: implement Converter.
  • Error handling: withThrowExceptions(false) + CsvToBean.getCapturedExceptions() để collect lỗi từng dòng.

Thay thế nhẹ: Jackson CSV

Nếu đã dùng Jackson JSON, có thể dùng jackson-dataformat-csv – API nhất quán, ít dependency hơn.