我正在使用opencsv将Java bean写入带有标头的CSV文件。文件名包含当前日期。如果用户在同一天再次运行它,它会附加到该文件,但会添加另一个标题行。
如何附加到文件但没有列标题。
public class CSVExport {
final File USERHOME = new File(System.getProperty("user.home"));
final List<saleExport> listSaleExport = new ArrayList<>();
final ObjectMapper mapper = new ObjectMapper();
public void createCsvFile(String Region, Map<String, String> currentSale) throws IOException {
mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
// use column position mapping strategy for no headers?
LocalDate today = LocalDate.now();
final SaleExport saleExport = mapper.convertValue(currentSale, SaleExport.class);
listSaleExport.add(saleExport);
writeToFile(today +" LA.csv", listSaleExport);
}
public void writeToFile(String filename, List<listSaleExport> listSaleExport) throws IOException {
File file = new File(PROCESSED_DIR +"\\", "filename");
if (!file.exists()) {
try {
Writer writer = new FileWriter(PROCESSED_DIR +"\\" +filename, true);
StatefulBeanToCsvBuilder<listSaleExport> beanToCsv = new StatefulBeanToCsvBuilder<>(writer);
StatefulBeanToCsv<listSaleExport> beanWriter = beanToCsv.build();
beanWriter.write(listSaleExport);
writer.close();
} catch (Exception ex) {
System.out.println("Error : " + ex.getMessage());
}
} else {
try {
Writer writer = new FileWriter(PROCESSED_DIR +"\\" +"filename");
StatefulBeanToCsvBuilder<listSaleExport> beanToCsv = new StatefulBeanToCsvBuilder<>(writer);
StatefulBeanToCsv<listSaleExport> beanWriter = beanToCsv.build();
beanWriter.write(listSaleExport);
writer.close();
} catch (Exception ex) {
System.out.println("Error : " + ex.getMessage());
}
}
}
}
答案 0 :(得分:3)
好的。当我们在opencsv中写作时,追加是我们没有想到的,因为它有潜在的风险(出了问题,你可能会破坏什么是好文件)所以写作更受青睐。
那说在sourceforge中打开一个bug或功能请求,如果有足够的兴趣,我们将尝试在4.3版本中获取它(4.2已经预订固定)。
如果你想解决这个问题,那就创建你自己的扩展MappingStrategy的HeaderColumnNameMappingStrategy类,并且你需要的只是在generateHeader方法上覆盖一个空字符串数组。您可以查看ColumnPositionMappingStrategy中的代码,看看我在说什么。这样可以防止写入标题。在这种情况下,您只需要在else部分使用它。
希望有所帮助。
:)
答案 1 :(得分:0)
我不知道该功能是否最终已添加到OpenCSV中。现在最新版本是5.1,但我还没有阅读任何内容...
正如我在another question中发布的那样,我将其更新为5.1后就可以使用:
需要同时具有特定字段标题(@CsvBindByName)和位置(@CsvBindByPosition)的CSV,所以我已经必须制定自己的MappingStrategy。
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生成:
public class ExportGenericCSV<T> {
private static final Logger logger = LoggerFactory.getLogger(ExportGenericCSV.class);
private final char DEFAULT_QUOTE_CHARACTER = CSVWriter.NO_QUOTE_CHARACTER;
private final char CSV_SEPARATOR = CSVWriter.DEFAULT_SEPARATOR;
public void writeToFile(String fileName, List<T> content){
writeList(fileName, content, true);
}
public void appendToFile(String fileName, List<T> content){
writeList(fileName, content, false, StandardOpenOption.APPEND);
}
@SuppressWarnings("unchecked")
private void writeList(String fileName, List<T> exports, boolean addHeader, OpenOption...openOptions){
if(exports == null || exports.isEmpty()) return;
try (Writer writer = Files.newBufferedWriter(Paths.get(fileName), openOptions)){
CustomMappingStrategy<T> mapping = new CustomMappingStrategy<T>(addHeader);
mapping.setType((Class<? extends T>) exports.get(0).getClass());
StatefulBeanToCsv<T> beanToCsv = new StatefulBeanToCsvBuilder<T>(writer)
.withQuotechar(DEFAULT_QUOTE_CHARACTER)
.withSeparator(CSV_SEPARATOR)
.withMappingStrategy(mapping)
.build();
beanToCsv.write(exports);
writer.flush();
writer.close();
} catch (IOException e) {
logger.error(e.getMessage(), e);
} catch (CsvDataTypeMismatchException e) {
logger.error(e.getMessage(), e);
} catch (CsvRequiredFieldEmptyException e) {
logger.error(e.getMessage(), e);
}
}
}
这样,当您需要导出项目列表时,可以使用:
ExportGenericCSV<ExportedClass> exporter = new ExportGenericCSV<ExportedClass>();
然后使用exporter.writeToFile(...)
或exporter.appendToFile(...)