带列 headers 的 StatefulBeanToCsv
StatefulBeanToCsv with Column headers
我正在使用 opencsv-4.0
编写一个 csv 文件,我需要在输出文件中添加列 headers。
这是我的代码。
public static void buildProductCsv(final List<Product> product,
final String filePath) {
try {
Writer writer = new FileWriter(filePath);
// mapping of columns with their positions
ColumnPositionMappingStrategy<Product> mappingStrategy = new ColumnPositionMappingStrategy<Product>();
// Set mappingStrategy type to Product Type
mappingStrategy.setType(Product.class);
// Fields in Product Bean
String[] columns = new String[] { "productCode", "MFD", "EXD" };
// Setting the colums for mappingStrategy
mappingStrategy.setColumnMapping(columns);
StatefulBeanToCsvBuilder<Product> builder = new StatefulBeanToCsvBuilder<Product>(writer);
StatefulBeanToCsv<Product> beanWriter = builder.withMappingStrategy(mappingStrategy).build();
// Writing data to csv file
beanWriter.write(product);
writer.close();
log.info("Your csv file has been generated!");
} catch (Exception ex) {
log.warning("Exception: " + ex.getMessage());
}
}
以上代码创建了一个包含数据的 csv 文件。但它不包括该文件中的列 headers。
如何添加列 headers 以输出 csv?
ColumnPositionMappingStrategy#generateHeader returns 空数组
/**
* This method returns an empty array.
* The column position mapping strategy assumes that there is no header, and
* thus it also does not write one, accordingly.
* @return An empty array
*/
@Override
public String[] generateHeader() {
return new String[0];
}
如果您从 BeanToCsv 构建器中删除 MappingStrategy
// replace
StatefulBeanToCsv<Product> beanWriter = builder.withMappingStrategy(mappingStrategy).build();
// with
StatefulBeanToCsv<Product> beanWriter = builder.build();
它会将产品的 class 成员写入 CSV header
如果您的产品 class 成员姓名是
"productCode", "MFD", "EXD"
这应该是正确的解决方案
否则,添加@CsvBindByName 注解
import com.opencsv.bean.CsvBindByName;
import com.opencsv.bean.StatefulBeanToCsv;
import com.opencsv.bean.StatefulBeanToCsvBuilder;
import java.io.FileWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
public class CsvTest {
public static void main(String[] args) throws Exception {
Writer writer = new FileWriter(fileName);
StatefulBeanToCsvBuilder<Product> builder = new StatefulBeanToCsvBuilder<>(writer);
StatefulBeanToCsv<Product> beanWriter = builder.build();
List<Product> products = new ArrayList<>();
products.add(new Product("1", "11", "111"));
products.add(new Product("2", "22", "222"));
products.add(new Product("3", "33", "333"));
beanWriter.write(products);
writer.close();
}
public static class Product {
@CsvBindByName(column = "productCode")
String id;
@CsvBindByName(column = "MFD")
String member2;
@CsvBindByName(column = "EXD")
String member3;
Product(String id, String member2, String member3) {
this.id = id;
this.member2 = member2;
this.member3 = member3;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getMember2() {
return member2;
}
public void setMember2(String member2) {
this.member2 = member2;
}
public String getMember3() {
return member3;
}
public void setMember3(String member3) {
this.member3 = member3;
}
}
}
输出:
"EXD","MFD","PRODUCTCODE"
"111","11","1"
"222","22","2"
"333","33","3"
注意; class,getters 和 setters 需要 public,因为 OpenCSV 库使用反射
我可能在这里遗漏了一些明显的东西,但你不能将你的 header 字符串附加到作者 object 吗?
Writer writer = new FileWriter(filePath);
writer.append("header1, header2, header3, ...etc \n");
// This will be followed by your code with BeanToCsvBuilder
// Note: the terminating \n might differ pending env.
您可以通过注释追加
public void export(List<YourObject> list, PrintWriter writer) throws Exception {
writer.append( buildHeader( YourObject.class ) );
StatefulBeanToCsvBuilder<YourObject> builder = new StatefulBeanToCsvBuilder<>( writer );
StatefulBeanToCsv<YourObject> beanWriter = builder.build();
beanWriter.write( mapper.map( list ) );
writer.close();
}
private String buildHeader(Class<YourObject> clazz) {
return Arrays.stream( clazz.getDeclaredFields() )
.filter( f -> f.getAnnotation( CsvBindByPosition.class ) != null
&& f.getAnnotation( CsvBindByName.class ) != null )
.sorted( Comparator.comparing( f -> f.getAnnotation( CsvBindByPosition.class ).position() ) )
.map( f -> f.getAnnotation( CsvBindByName.class ).column() )
.collect( Collectors.joining( "," ) ) + "\n";
}
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class YourObject {
@CsvBindByPosition(position = 0)
@CsvBindByName(column = "A")
private Long a;
@CsvBindByPosition(position = 1)
@CsvBindByName(column = "B")
private String b;
@CsvBindByPosition(position = 2)
@CsvBindByName(column = "C")
private String c;
}
您还可以覆盖 generateHeaders 方法和 return 设置的列映射,这将在 csv
中有 header 行
ColumnPositionMappingStrategy<Product> mappingStrategy = new ColumnPositionMappingStrategy<Product>() {
@Override
public String[] generateHeader(Product bean) throws CsvRequiredFieldEmptyException {
return this.getColumnMapping();
}
};
使用 HeaderColumnNameMappingStrategy 进行读取,然后使用相同的策略进行写入。在这种情况下,“相同”的意思不仅是相同 class,而且实际上是相同的 object.
来自 StatefulBeanToCsvBuilder.withMappingStrategy
的 javadoc:
It is perfectly legitimate to read a CSV source, take the mapping strategy from the read operation, and pass it in to this method for a write operation. This conserves some processing time, but, more importantly, preserves header ordering.
这样您将获得包含 headers 的 CSV,其中列的顺序与原始 CSV 的顺序相同。
使用 OpenCSV 5.4 为我工作。
我正在使用 opencsv-4.0
编写一个 csv 文件,我需要在输出文件中添加列 headers。
这是我的代码。
public static void buildProductCsv(final List<Product> product,
final String filePath) {
try {
Writer writer = new FileWriter(filePath);
// mapping of columns with their positions
ColumnPositionMappingStrategy<Product> mappingStrategy = new ColumnPositionMappingStrategy<Product>();
// Set mappingStrategy type to Product Type
mappingStrategy.setType(Product.class);
// Fields in Product Bean
String[] columns = new String[] { "productCode", "MFD", "EXD" };
// Setting the colums for mappingStrategy
mappingStrategy.setColumnMapping(columns);
StatefulBeanToCsvBuilder<Product> builder = new StatefulBeanToCsvBuilder<Product>(writer);
StatefulBeanToCsv<Product> beanWriter = builder.withMappingStrategy(mappingStrategy).build();
// Writing data to csv file
beanWriter.write(product);
writer.close();
log.info("Your csv file has been generated!");
} catch (Exception ex) {
log.warning("Exception: " + ex.getMessage());
}
}
以上代码创建了一个包含数据的 csv 文件。但它不包括该文件中的列 headers。
如何添加列 headers 以输出 csv?
ColumnPositionMappingStrategy#generateHeader returns 空数组
/**
* This method returns an empty array.
* The column position mapping strategy assumes that there is no header, and
* thus it also does not write one, accordingly.
* @return An empty array
*/
@Override
public String[] generateHeader() {
return new String[0];
}
如果您从 BeanToCsv 构建器中删除 MappingStrategy
// replace
StatefulBeanToCsv<Product> beanWriter = builder.withMappingStrategy(mappingStrategy).build();
// with
StatefulBeanToCsv<Product> beanWriter = builder.build();
它会将产品的 class 成员写入 CSV header
如果您的产品 class 成员姓名是
"productCode", "MFD", "EXD"
这应该是正确的解决方案
否则,添加@CsvBindByName 注解
import com.opencsv.bean.CsvBindByName;
import com.opencsv.bean.StatefulBeanToCsv;
import com.opencsv.bean.StatefulBeanToCsvBuilder;
import java.io.FileWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
public class CsvTest {
public static void main(String[] args) throws Exception {
Writer writer = new FileWriter(fileName);
StatefulBeanToCsvBuilder<Product> builder = new StatefulBeanToCsvBuilder<>(writer);
StatefulBeanToCsv<Product> beanWriter = builder.build();
List<Product> products = new ArrayList<>();
products.add(new Product("1", "11", "111"));
products.add(new Product("2", "22", "222"));
products.add(new Product("3", "33", "333"));
beanWriter.write(products);
writer.close();
}
public static class Product {
@CsvBindByName(column = "productCode")
String id;
@CsvBindByName(column = "MFD")
String member2;
@CsvBindByName(column = "EXD")
String member3;
Product(String id, String member2, String member3) {
this.id = id;
this.member2 = member2;
this.member3 = member3;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getMember2() {
return member2;
}
public void setMember2(String member2) {
this.member2 = member2;
}
public String getMember3() {
return member3;
}
public void setMember3(String member3) {
this.member3 = member3;
}
}
}
输出:
"EXD","MFD","PRODUCTCODE"
"111","11","1"
"222","22","2"
"333","33","3"
注意; class,getters 和 setters 需要 public,因为 OpenCSV 库使用反射
我可能在这里遗漏了一些明显的东西,但你不能将你的 header 字符串附加到作者 object 吗?
Writer writer = new FileWriter(filePath);
writer.append("header1, header2, header3, ...etc \n");
// This will be followed by your code with BeanToCsvBuilder
// Note: the terminating \n might differ pending env.
您可以通过注释追加
public void export(List<YourObject> list, PrintWriter writer) throws Exception {
writer.append( buildHeader( YourObject.class ) );
StatefulBeanToCsvBuilder<YourObject> builder = new StatefulBeanToCsvBuilder<>( writer );
StatefulBeanToCsv<YourObject> beanWriter = builder.build();
beanWriter.write( mapper.map( list ) );
writer.close();
}
private String buildHeader(Class<YourObject> clazz) {
return Arrays.stream( clazz.getDeclaredFields() )
.filter( f -> f.getAnnotation( CsvBindByPosition.class ) != null
&& f.getAnnotation( CsvBindByName.class ) != null )
.sorted( Comparator.comparing( f -> f.getAnnotation( CsvBindByPosition.class ).position() ) )
.map( f -> f.getAnnotation( CsvBindByName.class ).column() )
.collect( Collectors.joining( "," ) ) + "\n";
}
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class YourObject {
@CsvBindByPosition(position = 0)
@CsvBindByName(column = "A")
private Long a;
@CsvBindByPosition(position = 1)
@CsvBindByName(column = "B")
private String b;
@CsvBindByPosition(position = 2)
@CsvBindByName(column = "C")
private String c;
}
您还可以覆盖 generateHeaders 方法和 return 设置的列映射,这将在 csv
中有 header 行ColumnPositionMappingStrategy<Product> mappingStrategy = new ColumnPositionMappingStrategy<Product>() {
@Override
public String[] generateHeader(Product bean) throws CsvRequiredFieldEmptyException {
return this.getColumnMapping();
}
};
使用 HeaderColumnNameMappingStrategy 进行读取,然后使用相同的策略进行写入。在这种情况下,“相同”的意思不仅是相同 class,而且实际上是相同的 object.
来自 StatefulBeanToCsvBuilder.withMappingStrategy
的 javadoc:
It is perfectly legitimate to read a CSV source, take the mapping strategy from the read operation, and pass it in to this method for a write operation. This conserves some processing time, but, more importantly, preserves header ordering.
这样您将获得包含 headers 的 CSV,其中列的顺序与原始 CSV 的顺序相同。
使用 OpenCSV 5.4 为我工作。