在没有 headers 的情况下附加到 CSV 文件
Appending to CSV file without headers
我正在使用 opencsv 将 Java bean 写入具有 headers 的 CSV 文件。文件名包含当前日期。如果用户在同一天第二次运行它,它会附加到文件,但会添加另一行 header。
如何追加到文件但没有列 headers.
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());
}
}
}
}
不错。当我们在 opencsv 中写入时,附加是我们没有考虑太多的事情,因为它有潜在的风险(出现问题你可能会破坏一个好的文件)所以 write 更受欢迎。
那是说在 sourceforge 中提出错误或功能请求,如果有足够的兴趣,我们将尝试在 4.3 版本中获得它(4.2 已预订)。
如果您想解决这个问题,请创建您自己的 MappingStrategy class that extends the HeaderColumnNameMappingStrategy and all you need there is a override on the generateHeader method to return an empty String array. You can look at the code in ColumnPositionMappingStrategy 看看我在说什么。这将防止 header 被写入。在这种情况下,您只需要在 else 部分使用它。
希望对您有所帮助。
:)
我不知道该功能是否最终添加到 OpenCSV 中。现在最新版本是 5.1,我还没有读到任何关于它的信息...
正如我在 another question 中发布的那样,我在更新到 5.1 后开始工作:
需要具有特定字段 headers (@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();
}
}
我还制作了一个通用导出器 class,以简化 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(...)
我正在使用 opencsv 将 Java bean 写入具有 headers 的 CSV 文件。文件名包含当前日期。如果用户在同一天第二次运行它,它会附加到文件,但会添加另一行 header。
如何追加到文件但没有列 headers.
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());
}
}
}
}
不错。当我们在 opencsv 中写入时,附加是我们没有考虑太多的事情,因为它有潜在的风险(出现问题你可能会破坏一个好的文件)所以 write 更受欢迎。
那是说在 sourceforge 中提出错误或功能请求,如果有足够的兴趣,我们将尝试在 4.3 版本中获得它(4.2 已预订)。
如果您想解决这个问题,请创建您自己的 MappingStrategy class that extends the HeaderColumnNameMappingStrategy and all you need there is a override on the generateHeader method to return an empty String array. You can look at the code in ColumnPositionMappingStrategy 看看我在说什么。这将防止 header 被写入。在这种情况下,您只需要在 else 部分使用它。
希望对您有所帮助。
:)
我不知道该功能是否最终添加到 OpenCSV 中。现在最新版本是 5.1,我还没有读到任何关于它的信息...
正如我在 another question 中发布的那样,我在更新到 5.1 后开始工作:
需要具有特定字段 headers (@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();
}
}
我还制作了一个通用导出器 class,以简化 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(...)