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

dja*_*fan 4 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

wol*_*000 5

我已将 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();
    }

}
Run Code Online (Sandbox Code Playgroud)

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