想从 beanIO 字段名称标签在 csv 中写入 header

want to write header in csv from beanIO field name tag

我想在 csv 文件中写一个 header 因为我的文本文件不包含任何 header 所以我想从 beanIO 字段名称标签写它

我有一个带有两个流的 beanIO,一个用于读取,另一个用于写入

这是输入文件.... textInput.txt-
1 约翰露 BA xxx
1sam hart MA yyy

public static void main(String[] args) throws Exception {

    StreamFactory factory = StreamFactory.newInstance();

    factory.load("C:\Users\PV5057094\Demo_workspace\XlsxMapper\src\main\resources\Employee.xml");


BeanReader br = factory.createReader("EmployeeInfo",new File("C:\Temp\Soc\textInput.txt"));

    BeanWriter out = factory.createWriter("EmployeeInfoCSV", new File("C:\Temp\Soc\output.csv"));



    Object record;

    while ((record=br.read())!=null) {


        out.write(record);

        System.out.println("Record Written:" + record.toString());

    }

    // in.close();
    out.flush();
    out.close();
   }

}


BeanIO-

<?xml version="1.0" encoding="UTF-8"?>
<beanio xmlns="http://www.beanio.org/2012/03"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.beanio.org/2012/03 http://www.beanio.org/2012/03/mapping.xsd">

    <stream name="EmployeeInfo" format="fixedlength">

        <record name="a" minOccurs="0" maxOccurs="unbounded"
            class="com.aexp.gmnt.imc.record.submission.Employee">
            <field name="record" length="1" literal="1" rid="true"/>
            <field name="firstName" length="5"/>
            <field name="lastName" length="5"/>
            <field name="title" length="5"/>
            <field name="filler" length="5"/>
        </record>

    </stream>


    <stream name="EmployeeInfoCSV" format="csv">
        <record name="a" minOccurs="0" maxOccurs="unbounded"
            class="com.aexp.gmnt.imc.record.submission.Employee">
            <field name="record" length="1" literal="1" rid="true"/>
            <field name="firstName" length="5"/>
            <field name="lastName" length="5"/>
            <field name="title" length="5"/>
            <field name="filler" length="5"/>
        </record>
    </stream>
</beanio>

预期输出-

记录、名字、姓氏、职务、填充人
1,john,dew,BA,xxx
1,sam,hart,MA,yyy

您必须在 EmployeeInfoCSV 流定义中定义一个新的 record,它将包含列名作为该字段的默认值,例如

<record name="headers" minOccurs="1" maxOccurs="1">
  <field name="recordColumn" default="Record"/>

然后你必须告诉你的BeanWriter先写出一条"headers"的记录,然后再输出文件的其余部分。

out.write("headers", null);

您还必须将 CSV 流中 a 记录的 length 属性更改为 maxLength,否则您将在输出中填充内容,但它看起来仍然像一个固定长度的格式。

改变

<field name="firstName" length="5"/>

<field name="firstName" maxLength="5"/>

然后把这些放在一起:

public static void main(String[] args) throws Exception {

  StreamFactory factory = StreamFactory.newInstance();
  factory.load("C:\Users\PV5057094\Demo_workspace\XlsxMapper\src\main\resources\Employee.xml");

  BeanReader br = factory.createReader("EmployeeInfo",new File("C:\Temp\Soc\textInput.txt"));
  BeanWriter out = factory.createWriter("EmployeeInfoCSV", new File("C:\Temp\Soc\output.csv"));

  // write the column headers to the output file
  out.write("headers", null);

  Object record;
  while ((record=br.read())!=null) {
    out.write(record);
    System.out.println("Record Written:" + record.toString());
  }

  br.close();  // yes, also close the reader
  out.flush();
  out.close();
}

和映射文件:

<?xml version="1.0" encoding="UTF-8"?>
<beanio xmlns="http://www.beanio.org/2012/03"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.beanio.org/2012/03 http://www.beanio.org/2012/03/mapping.xsd">

  <stream name="EmployeeInfo" format="fixedlength">
      <record name="a" minOccurs="0" maxOccurs="unbounded"
          class="com.aexp.gmnt.imc.record.submission.Employee">
          <field name="record" length="1" literal="1" rid="true"/>
          <field name="firstName" length="5"/>
          <field name="lastName" length="5"/>
          <field name="title" length="5"/>
          <field name="filler" length="5"/>
      </record>
  </stream>

  <stream name="EmployeeInfoCSV" format="csv">
    <record name="headers" minOccurs="1" maxOccurs="1">
      <field name="recordColumn" default="Record"/>
      <field name="firstNameColumn" default="FirstName"/>
      <field name="lastNameColumn" default="LastName"/>
      <field name="titleColumn" default="Title"/>
      <field name="fillerColumn" default="Filler"/>
    </record>
    <record name="a" minOccurs="0" maxOccurs="unbounded" 
            class="com.aexp.gmnt.imc.record.submission.Employee">
      <field name="record" length="1"/>
      <field name="firstName" maxLength="5"/>
      <field name="lastName" maxLength="5"/>
      <field name="title" maxLength="5"/>
      <field name="filler" maxLength="5"/>
    </record>
  </stream>
</beanio>

我已经编写了一个实用程序方法来根据原始记录中设置的 @Field.name 属性动态创建 Header 记录,它可能被认为是 hack,但它比创建新记录更好class 或创建一个 XML 文件只是为了打印 CSV header 行 IMO。

import java.io.ByteArrayOutputStream;
import java.io.OutputStreamWriter;

import org.beanio.BeanWriter;
import org.beanio.StreamFactory;
import org.beanio.annotation.Field;
import org.beanio.annotation.Record;
import org.beanio.builder.FieldBuilder;
import org.beanio.builder.RecordBuilder;
import org.beanio.builder.StreamBuilder;

public class Headers {

  public static void main(String[] args) {

    final String factoryName = "comma delimited csv factory";
    final String headerName = "CarHeader";

    final var builder = new StreamBuilder(factoryName)
        .format("csv")
        .addRecord(Headers.of(Car.class, headerName))
        .addRecord(Car.class)
        ;

    final var factory = StreamFactory.newInstance();
    factory.define(builder);

    final ByteArrayOutputStream bout = new ByteArrayOutputStream();
    final BeanWriter writer = factory.createWriter(factoryName, new OutputStreamWriter(bout));
    try {
      writer.write(headerName, null);
      writer.write(new Car("Ford Ka", 2016));
      writer.write(new Car("Ford Fusion", 2020));
    } finally {
      writer.close();
    }

    System.out.println(bout.toString());
//    Model,Year
//    Ford Ka,2016
//    Ford Fusion,2020
  }

  public static RecordBuilder of(Class<?> clazz, String name) {
    final RecordBuilder builder = new RecordBuilder(name)
        .order(1);
    if (clazz.getAnnotation(Record.class) == null) {
      throw new IllegalArgumentException("Class must be a BeanIo Record, annotated with @Record");
    }
    for (java.lang.reflect.Field classField : clazz.getDeclaredFields()) {

      final Field fieldAnnotation = classField.getAnnotation(Field.class);
      if (fieldAnnotation == null) {
        continue;
      }
      builder.addField(
          new FieldBuilder(fieldAnnotation.name())
              .defaultValue(fieldAnnotation.name())
      );

    }
    return builder;
  }

  @Record(order = 2)
  static class Car {

    @Field(name = "Model")
    private String model;

    @Field(name = "Year")
    private Integer year;

    public Car(String model, Integer year) {
      this.model = model;
      this.year = year;
    }

    public String getModel() {
      return model;
    }

    public Integer getYear() {
      return year;
    }

    public Car setModel(String model) {
      this.model = model;
      return this;
    }

    public Car setYear(Integer year) {
      this.year = year;
      return this;
    }
  }
}