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

使用Super CSV生成自定义分隔符CSV的报错解决与实现问询

Super CSV自定义分隔符及反射报错解决方案

报错原因

你遇到的反射错误完全是因为header数组的配置逻辑错误:

  • Super CSV的ICsvBeanWriter.write()方法传入的字段名数组,需要和JavaBean的属性名完全匹配,你在字段名后加了冒号,导致框架去Employee类中查找名为id:、name:的属性,自然找不到
  • 你不需要修改Bean类的属性名,展示用的带冒号的表头和Bean字段映射是两套配置,分开处理即可

完整解决方案

分两种场景匹配你的需求:

场景1:用冒号作为CSV分隔符(替代默认逗号)

Super CSV支持通过CsvPreference自定义分隔符、引号字符等规则,默认会自动给包含分隔符、换行符、引号的字段加双引号包裹,刚好匹配你“字段含冒号自动加引号”的要求。
修正后的代码如下:

import org.supercsv.io.CsvBeanWriter;
import org.supercsv.io.ICsvBeanWriter;
import org.supercsv.prefs.CsvPreference;
import org.supercsv.cellprocessor.*;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

public class SuperCsvWriter{
    public static void main(String ar[]){
        List<Employee> emps = generateDemoData();
        StringWriter writer = new StringWriter();
        // 自定义CSV配置:双引号作为包裹符,冒号作为分隔符,换行符用\n
        CsvPreference customPref = new CsvPreference.Builder('"', ':', "\n").build();
        ICsvBeanWriter beanWriter = new CsvBeanWriter(writer, customPref);
        
        // 两套配置分开:displayHeader是输出的表头,fieldMapping是对应Bean的属性名
        final String[] displayHeader = new String[] {"id:", "name:", "age:", "Country"};
        final String[] fieldMapping = new String[] {"id", "name", "age", "country"};
        final CellProcessor[] processors  = getProcessors();
        
        // 写展示用的表头
        beanWriter.writeHeader(displayHeader);
        for(Employee emp: emps){
            // 写字段用Bean属性映射数组
            beanWriter.write(emp, fieldMapping, processors);
        }
        beanWriter.close();
        System.out.println("CSV Data\n"+writer.toString());
    }

    private static CellProcessor[] getProcessors(){
        final CellProcessor[] processors = new CellProcessor[]{
            new UniqueHashCode(),//ID
            new NotNull(), //Name
            new Optional(),//Age
            new Optional() //Country
        };
        return processors;
    }

    private static List<Employee> generateDemoData(){
        List<Employee> empsToAdd = new ArrayList<Employee>();
        Employee emp = new Employee();
        emp.setId("1");
        emp.setName("Pankaj, saha");
        emp.setAge(":30");

        Employee emp1 = new Employee();
        emp1.setId("2");
        emp1.setName("Timber:Hups");
        emp1.setAge(":10");
        emp1.setCountry("USA");

        empsToAdd.add(emp);
        empsToAdd.add(emp1);
        return empsToAdd;
    }
}

// Employee类要补全getter、setter方法,否则反射无法读取属性
class Employee{
    private String id;
    private String name;
    private String age;
    private String country;

    public String getId() {return id;}
    public void setId(String id) {this.id = id;}
    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
    public String getAge() {return age;}
    public void setAge(String age) {this.age = age;}
    public String getCountry() {return country;}
    public void setCountry(String country) {this.country = country;}
}

场景2:分隔符保留逗号,仅字段内容含冒号时自动加双引号

如果你的需求是分隔符还是用逗号,只是要求只要字段里有冒号就加双引号,只需要自定义QuoteRule即可,不需要修改分隔符:

// 自定义配置:保留默认逗号分隔,只要字段包含冒号就自动加双引号
CsvPreference customPref = new CsvPreference.Builder(CsvPreference.STANDARD_PREFERENCE)
        .useQuoteMode((column, context) -> column != null && column.contains(":"))
        .build();

注意事项

  • 必须保证Employee类的所有属性都有public的getter、setter方法,否则Super CSV的反射读取会失败
  • 原代码中的Sytem为拼写错误,修正为System即可
  • 如果你需要其他自定义引号规则,直接修改useQuoteMode里的判断逻辑即可

内容的提问来源于stack exchange,提问作者Jeet

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 14:24:04