java 带有列标题的 StatefulBeanToCsv

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/46072947/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 09:02:39  来源:igfitidea点击:

StatefulBeanToCsv with Column headers

javacsvopencsv

提问by Bishan

I am using opencsv-4.0to write a csv file and I need to add column headers in output file.

我正在opencsv-4.0编写一个 csv 文件,我需要在输出文件中添加列标题。

Here is my code.

这是我的代码。

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

}

Above code create a csv file with data. But it not include column headers in that file.

上面的代码创建一个包含数据的 csv 文件。但它不包括该文件中的列标题。

How could I add column headers to output csv?

如何将列标题添加到输出 csv?

回答by Jim West

ColumnPositionMappingStrategy#generateHeader returns empty array

ColumnPositionMappingStrategy#generateHeader 返回空数组

/**
 * 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];
}

If you remove MappingStrategy from BeanToCsv builder

如果您从 BeanToCsv 构建器中删除 MappingStrategy

// replace 
StatefulBeanToCsv<Product> beanWriter = builder.withMappingStrategy(mappingStrategy).build();
// with
StatefulBeanToCsv<Product> beanWriter = builder.build(); 

It will write Product's class members as CSV header

它将产品的类成员写为 CSV 标头

If your Product class members names are

如果您的 Product 类成员名称是

"productCode", "MFD", "EXD"

This should be the right solution

这应该是正确的解决方案

Else, add @CsvBindByName annotation

否则,添加@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;
        }
    }

}

Output:

输出:

"EXD","MFD","PRODUCTCODE"

"111","11","1"

"222","22","2"

"333","33","3"

“EXD”、“MFD”、“产品代码”

“111”、“11”、“1”

“222”、“22”、“2”

“333”、“33”、“3”

Pay attention; class, getters & setters needs to be public due to the use of Reflection by OpenCSV library

注意; 由于 OpenCSV 库使用反射,类、getter 和 setter 需要公开

回答by Ithar

I may have missed something obvious here but couldn't you just append your header String to the writer object?

我可能在这里遗漏了一些明显的内容,但您不能将标题字符串附加到 writer 对象吗?

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.

回答by Bruno Muehlbauer de Souza

You can append by annotation

您可以通过注释追加

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;

}

回答by fcecchin

Not so good, but the easiest way is just appending a header to writer object ...

不太好,但最简单的方法是将标头附加到 writer 对象...

        ...
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        OutputStreamWriter osw = new OutputStreamWriter(os);
        osw.append("PRODUCTCODE;EXD;MFD\n");
        CSVWriter writer = new CSVWriter(osw, ';', CSVWriter.NO_QUOTE_CHARACTER, CSVWriter.DEFAULT_ESCAPE_CHARACTER,
                CSVWriter.DEFAULT_LINE_END);
        StatefulBeanToCsv<Product> beanToCsv = new StatefulBeanToCsvBuilder<Product>(writer)
                .build();
        beanToCsv.write(linhas);