【问题标题】:want to write header in csv from beanIO field name tag想从 beanIO 字段名称标签写入 csv 中的标头
【发布时间】:2019-12-03 16:08:54
【问题描述】:

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

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

这是输入文件.... textInput.txt-
1john dew 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,约翰,露水,BA,xxx
1,山姆,哈特,MA,yyy

【问题讨论】:

  • 请同时添加您当前的输出

标签: java bean-io


【解决方案1】:

我已经编写了一个 utils 方法来根据原始记录中设置的@Field.name 属性动态创建一个标题记录,它可能被认为是一种 hack,但它比创建一个新类或创建一个 XML 文件更好打印 CSV 标题行 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;
    }
  }
}

【讨论】:

    【解决方案2】:

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

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

    然后你必须告诉你的BeanWriter在输出文件的其余部分之前先写出“标题”的记录。

    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>
    

    【讨论】:

    • 还有一件事,如果我在 BeanIO 中有段或列表,那段我必须打印 100 次,这可能与此有关
    • 这真的应该是一个新问题:-) BeanIO 可以处理它。该片段是您现有记录之一的子片段吗?
    • 我有一个像
    • 我真的认为你应该问一个新问题并解释你尝试了什么,输入和预期输出是什么,就像你对这个问题所做的那样。解释细分涉及的位置等。
    猜你喜欢
    • 1970-01-01
    • 2015-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多