You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Jackson反序列化含整行双引号包裹的CSV文件

使用jackson-dataformat-csv处理异常格式的CSV行

问题场景

给定如下格式的CSV文件:

firstName,lastName,address
"John,Doe,"Imaginary St. 42, 1234 Hometown""
Jane,Doe,"Castle St. 1, 5678 Littletown" 

需要将其反序列化为如下Java类的对象:

public class PersonRecord {
  private String firstName;
  private String lastName;
  private String address;

  // 可选:添加getter/setter,或配置Jackson直接访问字段(见下文)
}

核心挑战:部分行被整体用双引号包裹(需移除这层外层双引号),但address字段本身的值允许包含双引号,不能误删这些内部引号。

无需临时文件的最优方案

通过自定义Reader在流读取阶段预处理每行数据,直接修正格式后交给Jackson解析,全程无需生成临时文件。

1. 实现自定义行处理Reader

继承FilterReader,重写readLine方法,针对性移除行首尾的外层双引号:

import java.io.FilterReader;
import java.io.IOException;
import java.io.Reader;

public class LineCleaningReader extends FilterReader {

    protected LineCleaningReader(Reader in) {
        super(in);
    }

    @Override
    public String readLine() throws IOException {
        String line = super.readLine();
        if (line == null) {
            return null;
        }
        // 已知第一列不会被引号包裹,因此首尾均为双引号时才处理
        if (line.startsWith("\"") && line.endsWith("\"")) {
            return line.substring(1, line.length() - 1);
        }
        return line;
    }
}

2. 配置Jackson并完成解析

用自定义Reader包装原始输入流,结合CsvMapper完成反序列化:

import com.fasterxml.jackson.databind.MappingIterator;
import com.fasterxml.jackson.databind.introspect.JsonAutoDetect;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;

import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;

public class CsvParserDemo {
    public static void main(String[] args) throws IOException {
        CsvMapper mapper = new CsvMapper();
        
        // 可选配置:无需getter/setter,让Jackson直接访问类字段
        mapper.setVisibility(mapper.getSerializationConfig().getDefaultVisibilityChecker()
                .withFieldVisibility(JsonAutoDetect.Visibility.ANY)
                .withGetterVisibility(JsonAutoDetect.Visibility.NONE)
                .withSetterVisibility(JsonAutoDetect.Visibility.NONE)
                .withCreatorVisibility(JsonAutoDetect.Visibility.NONE));

        // 构建CSV schema:用首行作为列名映射到PersonRecord的字段
        CsvSchema schema = mapper.schemaFor(PersonRecord.class).withHeader();

        // 用自定义Reader包装原始文件输入流
        try (LineCleaningReader reader = new LineCleaningReader(new FileReader("your-file.csv"))) {
            MappingIterator<PersonRecord> iterator = mapper.readerFor(PersonRecord.class)
                    .with(schema)
                    .readValues(reader);

            List<PersonRecord> persons = new ArrayList<>();
            while (iterator.hasNext()) {
                persons.add(iterator.next());
            }

            // 验证解析结果
            persons.forEach(p -> {
                System.out.println("First Name: " + p.firstName);
                System.out.println("Last Name: " + p.lastName);
                System.out.println("Address: " + p.address);
                System.out.println("---");
            });
        }
    }
}

方案说明

  • 流预处理:自定义Reader在数据读取阶段直接修正格式,内存占用低,效率高于临时文件方案。
  • 安全处理:基于“第一列不会被引号包裹”的前提,仅移除首尾均为双引号的行的外层引号,避免误操作正常行。
  • 兼容字段内引号:Jackson的CSV解析器会自动处理address字段内部的双引号(比如示例中"Imaginary St. 42, 1234 Hometown"),无需额外处理。

内容的提问来源于stack exchange,提问作者Thomas W.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 09:40:27