使用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一起使用,我能够使其工作,但是这样做会使我的代码中出现“未检查的分配”警告。不理想;希望有一个优雅的解决方案?
答案 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 策略。不理想,但我可以正常工作。