【问题标题】:is there any way to retrieve the csvSchema used by a cvsMapper when it's read from the first line of a file?当从文件的第一行读取 cvsMapper 使用的 csvSchema 时,有什么方法可以检索它?
【发布时间】:2019-05-20 21:23:05
【问题描述】:

我设置了 CsvSchemaCsvMapper 以读取第一行中列名的 CSV 文件。

我需要能够对数据进行一些工作,更改特定字段,然后在保留列顺序的同时将数据写回。 我假设 CsvMapper 具有从第一行创建的内部模式,因为该地图具有所有正确的 key-value 对。 那么,有什么方法可以使用CsvMapperwriter 函数来使用该模式来排序输出数据?

CsvSchema schema = CsvSchema.emptySchema().withHeader();
CsvMapper mapper = new CsvMapper();
MappingIterator<Map<String, String>> it = this.mapper.readerFor(Map.class)
            .with(this.schema)
            .readValues(stream);

现在,我在第一列数据上收到了一个 CsvMappingException 表示“无法识别的列”,所以看起来它没有使用架构。

【问题讨论】:

  • 您使用哪个版本的Jackson?你的例子应该有效。您能否展示上述代码失败的示例 CSV 有效负载?
  • 版本 2.9.8。不幸的是,我无法发布有效载荷,有 100 多列,我认为看到它们不会有太大帮助。它们都是纯文本,数据中没有逗号。没有什么不寻常的。 代码有效。它获取输入数据,映射它就好了。失败的是作家。就像在黑暗中刺伤一样,我尝试了 this.mapper.writer().writeValueAsString(rows); 并在第一列得到了异常。

标签: java csv jackson fasterxml


【解决方案1】:

您可以使用从输入文件中读取的第一行中的架构构建SequenceWriterJackson 在后面使用 LinkedHashMap,因此,订单保持不变。假设您的 CSV 输入包含:

C1,name,type
I1,John,T1
I2,Adam,T2

您可以读取、更新和写入控制台,如下例所示:

import com.fasterxml.jackson.databind.MappingIterator;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.SequenceWriter;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;

import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.util.Map;

public class CsvApp {

    private CsvMapper csvMapper = new CsvMapper();

    private void handle() throws Exception {
        File csvFile = new File("./resource/test.csv").getAbsoluteFile();

        CsvSchema schema = CsvSchema.emptySchema().withHeader();
        MappingIterator<Map<String, String>> iterator = csvMapper.readerFor(Map.class).with(schema).readValues(csvFile);

        SequenceWriter writer = null;
        while (iterator.hasNext()) {
            final Map<String, String> row = iterator.next();
            if (writer == null) {
                writer = createWriter(row).writeValues(System.out);
            }

            // do something ...
            for (Map.Entry<String, String> item : row.entrySet()) {
                row.replace(item.getKey(), item.getValue() + "U");
            }

            // write back
            writer.write(row);
        }

        close(writer);
    }

    private ObjectWriter createWriter(Map<String, String> row) {
        CsvSchema.Builder writeSchema = new CsvSchema.Builder();
        writeSchema.setUseHeader(true);
        row.keySet().forEach(writeSchema::addColumn);

        return csvMapper.writerFor(Map.class).with(writeSchema.build());
    }

    private void close(Closeable closeable) throws IOException {
        if (closeable != null) {
            closeable.close();
        }
    }

    public static void main(String[] args) throws Exception {
        new CsvApp().handle();
    }
}

上面的代码打印:

C1,name,type
I1U,JohnU,T1U
I2U,AdamU,T2U

另见:

  1. jackson-dataformats-text - Overview

【讨论】:

  • 设置作家,我有:public void fill(InputStream stream) throws IOException { MappingIterator&lt;Map&lt;String, String&gt;&gt; it = this._mapper.readerFor(Map.class) .with(this._schema) .readValues(stream); while (it.hasNext()) { final Map&lt;String, String&gt; row = it.next(); this.rows.add(row); this._writer = createWriter(row); } it.forEachRemaining(this.rows::add); } 我怎样才能得到一个字符串的输出,而不是 system.out?
  • 使用 ByteArrayOutputStream 和 PrintStream 来捕获写入的输出,我设法让一切正常工作。感谢所有帮助
  • @JustinWright,我很高兴听到这个消息!因为你是新用户,请看一下:How does accepting an answer work?
猜你喜欢
  • 2010-09-27
  • 2021-03-22
  • 2021-08-16
  • 1970-01-01
  • 2017-08-27
  • 1970-01-01
  • 1970-01-01
  • 2021-03-25
  • 1970-01-01
相关资源
最近更新 更多