繁体   English   中英

为什么在写入文件时opencsv大写csv标头

[英]Why opencsv capitalizing csv headers while writing to file

使用 OpenCSV 4.6 将 Beans 写入 CSV 文件时,所有标题都变为大写。 尽管 bean 具有 @CsvBindByName 注释,但它正在更改为大写。

Java 豆:

public class ProjectInfo implements Serializable {

    @CsvBindByName(column = "ProjectName",required = true)
    private String projectName;

    @CsvBindByName(column = "ProjectCode",required = true)
    private String projectCode;

    @CsvBindByName(column = "Visibility",required = true)
    private String visibility;
    //setters and getters
}

主要方法

public static void main(String[] args) throws IOException {
    Collection<Serializable> projectInfos = getProjectsInfo();
    try(BufferedWriter writer = new BufferedWriter(new FileWriter("test.csv"))){
        StatefulBeanToCsvBuilder builder = new StatefulBeanToCsvBuilder(writer);
        StatefulBeanToCsv beanWriter = builder
                    .withSeparator(';')
                    .build();
        try {
              beanWriter.write(projectInfos.iterator());
              writer.flush();

         } catch (CsvDataTypeMismatchException | CsvRequiredFieldEmptyException  e) {
                throw new RuntimeException("Failed to download admin file");
            }
        }

    }

预期结果:

"ProjectCode";"ProjectName";"Visibility"
"ANY";"Country DU";"1"
"STD";"Standard";"1"
"TST";"Test";"1"
"CMM";"CMMTest";"1"

实际结果:

"PROJECTCODE";"PROJECTNAME";"VISIBILITY"
"ANY";"Country DU";"1"
"STD";"Standard";"1"
"TST";"Test";"1"
"CMM";"CMMTest";"1"

我没有使用 ColumnMappingStrategy 的选项,因为我必须将此方法构建为通用解决方案。 谁能建议我如何按原样编写标题?

发生这种情况是因为HeaderColumnNameMappingStrategy中的代码使用toUpperCase()来存储和检索字段名称。

您可以改用HeaderColumnNameTranslateMappingStrategy并通过反射创建映射。

    
    public class AnnotationStrategy extends HeaderColumnNameTranslateMappingStrategy
    {
        public AnnotationStrategy(Class<?> clazz)
        {
            Map<String,String> map=new HashMap<>();
            //To prevent the column sorting
            List<String> originalFieldOrder=new ArrayList<>();
            for(Field field:clazz.getDeclaredFields())
            {
                CsvBindByName annotation = field.getAnnotation(CsvBindByName.class);
                if(annotation!=null)
                {
                    map.put(annotation.column(),annotation.column());
                    originalFieldOrder.add(annotation.column());
                }
            }
            setType(clazz);
            setColumnMapping(map);
            //Order the columns as they were created
            setColumnOrderOnWrite((a,b) -> Integer.compare(originalFieldOrder.indexOf(a), originalFieldOrder.indexOf(b)));
        }
        
        @Override
        public String[] generateHeader(Object bean) throws CsvRequiredFieldEmptyException
        {
            String[] result=super.generateHeader(bean);
            for(int i=0;i<result.length;i++)
            {
                result[i]=getColumnName(i);
            }
            return result;
        }
    }

并且,假设只有一类项目(并且总是至少一个项目), beanWriter的创建必须扩展:

StatefulBeanToCsv beanWriter = builder.withSeparator(';')
    .withMappingStrategy(new AnnotationStrategy(projectInfos.iterator().next().getClass()))
    .build();

实际上, HeaderColumnNameMappingStrategy 使用toUpperCase() 来存储和检索字段名称。 为了使用自定义字段名称,您必须使用 @CsvBindByName 注释您的字段

@CsvBindByName(column = "Partner Code" )
private String partnerCode;

由于上述原因,默认情况下它将大写为 PARTNER CODE。 因此,为了控制它,我们必须编写一个实现HeaderColumnNameTranslateMappingStrategy的类。 使用 csv 5.0 和 java8 我已经实现了这样

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

import com.opencsv.bean.CsvBindByName;
import com.opencsv.bean.HeaderColumnNameTranslateMappingStrategy;
import com.opencsv.exceptions.CsvRequiredFieldEmptyException;

public class AnnotationStrategy<T> extends HeaderColumnNameTranslateMappingStrategy<T> {
    Map<String, String> columnMap = new HashMap<>();
    public AnnotationStrategy(Class<? extends T> clazz) {

        for (Field field : clazz.getDeclaredFields()) {
            CsvBindByName annotation = field.getAnnotation(CsvBindByName.class);
            if (annotation != null) {

                    columnMap.put(field.getName().toUpperCase(), annotation.column());
            }
        }
        setType(clazz);      
    }

    @Override
    public String getColumnName(int col) {
        String name = headerIndex.getByPosition(col);
        return name;
    }

    public String getColumnName1(int col) {
        String name = headerIndex.getByPosition(col);
        if(name != null) {
            name = columnMap.get(name);
        }
        return name;
    }
    @Override
    public String[] generateHeader(T bean) throws CsvRequiredFieldEmptyException {
        String[] result = super.generateHeader(bean);
        for (int i = 0; i < result.length; i++) {
            result[i] = getColumnName1(i);
        }
        return result;
    }
}

使用 opencsv 5.0 和 Java 8,我必须修改 AnnotationStrategy 类代码,如下所示:

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

import com.opencsv.bean.CsvBindByName;
import com.opencsv.bean.HeaderColumnNameTranslateMappingStrategy;
import com.opencsv.exceptions.CsvRequiredFieldEmptyException;

public class AnnotationStrategy<T> extends HeaderColumnNameTranslateMappingStrategy<T> {
    public AnnotationStrategy(Class<? extends T> clazz) {
        Map<String, String> map = new HashMap<>();
        for (Field field : clazz.getDeclaredFields()) {
            CsvBindByName annotation = field.getAnnotation(CsvBindByName.class);
            if (annotation != null) {
                map.put(annotation.column(), annotation.column());
            }
        }
        setType(clazz);
        setColumnMapping(map);
    }

    @Override
    public String[] generateHeader(T bean) throws CsvRequiredFieldEmptyException {
        String[] result = super.generateHeader(bean);
        for (int i = 0; i < result.length; i++) {
            result[i] = getColumnName(i);
        }
        return result;
    }
}

我尝试了其他解决方案,但是当属性名称和列名称不同时它不起作用。

我正在使用 5.6。 我的解决方案是重用该策略。

public class CsvRow {

    @CsvBindByName(column = "id")
    private String id;

    // Property name and column name are different
    @CsvBindByName(column = "country_code")
    private String countryCode;

}
// We are going to reuse this strategy
HeaderColumnNameMappingStrategy<CsvRow> strategy = new HeaderColumnNameMappingStrategy<>();
strategy.setType(CsvRow.class);

// Build the header line which respects the declaration order
// So its value will be "id,country_code"
String headerLine = Arrays.stream(CsvRow.class.getDeclaredFields())
        .map(field -> field.getAnnotation(CsvBindByName.class))
        .filter(Objects::nonNull)
        .map(CsvBindByName::column)
        .collect(Collectors.joining(","));

// Let the library to initialize column details in the strategy
try (StringReader stringReader = new StringReader(headerLine);
        CSVReader reader = new CSVReader(stringReader)) {
    CsvToBean<CsvRow> csv = new CsvToBeanBuilder<CsvRow>(reader)
            .withType(CsvRow.class)
            .withMappingStrategy(strategy)
            .build();
    for (CsvRow csvRow : csv) {}
}

该策略已准备好写入 csv 文件。

try (OutputStream outputStream = Files.newOutputStream(Path.of("test.csv"));
    OutputStreamWriter writer = new OutputStreamWriter(outputStream)) {

    StatefulBeanToCsv<CsvRow> csv = new StatefulBeanToCsvBuilder<CsvRow>(writer)
        .withMappingStrategy(strategy)
        .withThrowExceptions(true)
        .build();

    csv.write(csvRows);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM