杰克逊可以解析不同行具有不同模式的CSV文件吗?

时间:2014-12-02 14:32:20

标签: java parsing csv jackson

是否可以有效地使用Jackson jackson-dataformat-csv库(CsvSchemaCsvMapper等)解析CSV文件。当不同的行时该文件有不同的架构

我强调有效,因为我要解析非常大的文件(> 100,000,000行)并且应用程序对性能敏感。如果为每行中的每一列实例化一个新的Object / String,GC将拒绝我。我希望尽可能使用原语,例如31作为int返回。

如果是,推荐的方法是什么?

仅供参考,文件架构如下:ROW_TYPE|...。也就是说,每行的第一列表示列类型,对于给定的列类型,模式始终相同。然后其余列在行之间不同,具体取决于它们的列类型。 E.g:

1|"text1a"|2|3|4|true|"text2a"
2|3|"text"
1|"text1b"|5|6|7|false|"text2b"

目前我使用neo4j-csv库。

<dependency>
    <groupId>org.neo4j</groupId>
    <artifactId>neo4j-csv</artifactId>
    <version>2.2-SNAPSHOT</version>
</dependency>

它非常高效,并且产生非常少的垃圾。此外,它支持逐列读取条目,并且每次读取时都要指定类型 - 更多涉及,但更灵活。供参考,用法如下:

// do once per file
CharSeeker charSeeker = new BufferedCharSeeker(...), bufferSize);
int columnDelimiter = '|';
Extractors extractors = new Extractors();
Mark mark = new Mark();

// do repeatedly while parsing
charSeeker.seek(mark, columnDelimiters))
int eventType = charSeeker.extract(mark, extractors.int_()).intValue();

switch (eventType) {
    case 1: // parse row type 1
            break;
    case 2: // parse row type 2
            break;
...
...
}

我考虑切换的原因是我希望减少项目依赖性,因为我已经使用Jackson作为JSON,所以将它用于CSV(性能/功能待定)是有意义的。

1 个答案:

答案 0 :(得分:1)

虽然杰克逊没有自动支持在每行CsvSchema之间切换(这表明你需要进行两阶段处理;首先读取或绑定为String[]然后使用ObjectMapper.convertValue()),可能会使用现有的多态反序列化支持。这将取决于列命名的一些共性,所以我不知道它是否真实。

假设它正常工作,您需要一个具有与要使用的第一列的逻辑名匹配的属性的基类;然后具有类似匹配属性名称的子类型。 您可以在基类上使用@JsonTypeInfo,并使用&#39; name&#39;作为类型id;并在子类上使用@JsonTypeName,或使用@JsonSubTypes注释从基类引用。 也就是说,使用通常的Jackson配置。

如果这不起作用,两阶段处理可能不是一个糟糕的选择。这将导致所有单元格值被读取为不同的对象,但只要它们不被保留(即,您只在内存中保留一行数据),短期垃圾通常对GC没有问题(长 - 垃圾是一种昂贵的垃圾。)