使用OpenCSV,如何使用MappingStrategy附加到现有CSV?

时间:2019-03-04 00:47:52

标签: opencsv

使用OpenCSV,如何使用MappingStrategy附加到现有CSV?我有很多示例可以找到不使用Bean映射策略的地方,但我喜欢使用Bean策略的列映射的动态特性,并且希望以这种方式使其工作。这是我的代码,它仅将单行重写为CSV文件而不是追加。

我该如何解决?使用OpenCSV 4.5。注意:我将FileWriter设置为append = true。这种情况下无法正常工作。重新运行此方法仅会导致用标头和一行覆盖整个文件。

public void addRowToCSV(PerfMetric rowData) {
    File file = new File(PerfTestMetric.CSV_FILE_PATH);
    try {
        CSVWriter writer = new CSVWriter(new FileWriter(file, true));

        CustomCSVMappingStrategy<PerfMetric> mappingStrategy 
          = new CustomCSVMappingStrategy<>();
        mappingStrategy.setType(PerfMetric.class);

        StatefulBeanToCsv<PerfMetric> beanToCsv 
           = new StatefulBeanToCsvBuilder<PerfMetric>(writer)
            .withMappingStrategy(mappingStrategy)
            .withSeparator(',')
            .withApplyQuotesToAll(false)
            .build();

        try {
            beanToCsv.write(rowData);
        } catch (CsvDataTypeMismatchException e) {
            e.printStackTrace();
        } catch (CsvRequiredFieldEmptyException e) {
            e.printStackTrace();
        }
        writer.flush();
        writer.close();
    } catch (IOException e) {
            e.printStackTrace();
    }
}

或者,通常的模式是将所有行加载到列表中,然后重新写入整个文件吗?通过编写两个MappingStrategy映射策略,然后有条件地将它们与if-file-exists一起使用,我能够使其工作,但是这样做会使我的代码中出现“未检查的分配”警告。不理想;希望有一个优雅的解决方案?

2 个答案:

答案 0 :(得分:1)

我已经将OpenCSV更新到版本5.1,并且可以正常工作。就我而言,我需要CSV标头具有特定的名称和位置,因此我同时使用@CsvBindByName和@CsvBindByPosition,并且需要创建自定义MappingStrategy使其正常工作。

稍后,我需要编辑MappingStrategy以启用附加功能,因此当它处于附加模式时,我不需要生成CSV标头。

public class CustomMappingStrategy<T> extends ColumnPositionMappingStrategy<T> {
    private boolean useHeader=true;

    public CustomMappingStrategy(){
    }

    public CustomMappingStrategy(boolean useHeader) {
        this.useHeader = useHeader;
    }

    @Override
    public String[] generateHeader(T bean) throws CsvRequiredFieldEmptyException {
        final int numColumns = FieldUtils.getAllFields(bean.getClass()).length;
        super.setColumnMapping(new String[numColumns]);

        if (numColumns == -1) {
            return super.generateHeader(bean);
        }

        String[] header = new String[numColumns];

        if(!useHeader){
            return ArrayUtils.EMPTY_STRING_ARRAY;
        }
        BeanField<T, Integer> beanField;
        for (int i = 0; i < numColumns; i++){
            beanField = findField(i);
            String columnHeaderName = extractHeaderName(beanField);
            header[i] = columnHeaderName;
        }

        return header;
    }

    private String extractHeaderName(final BeanField<T, Integer> beanField){
        if (beanField == null || beanField.getField() == null || beanField.getField().getDeclaredAnnotationsByType(CsvBindByName.class).length == 0){
            return StringUtils.EMPTY;
        }

        //return value of CsvBindByName annotation
        final CsvBindByName bindByNameAnnotation = beanField.getField().getDeclaredAnnotationsByType(CsvBindByName.class)[0];
        return bindByNameAnnotation.column();
    }

}

现在,如果您使用默认构造函数,则会将标头添加到生成的CSV中,并使用布尔值告诉您添加标头或忽略标头。

答案 1 :(得分:0)

我从来没有找到这个问题的答案,所以我最终要做的是在存在.csv文件的情况下执行分支if条件。如果文件存在,则使用 MappingStrategyWithoutHeader 策略,如果文件不存在,则使用 MappingStrategyWithHeader 策略。不理想,但我可以正常工作。