使用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
相关产品推荐
相关产品推荐

