是否可以有效地使用Jackson jackson-dataformat-csv
库(CsvSchema
,CsvMapper
等)解析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(性能/功能待定)是有意义的。
答案 0 :(得分:1)
虽然杰克逊没有自动支持在每行CsvSchema
之间切换(这表明你需要进行两阶段处理;首先读取或绑定为String[]
然后使用ObjectMapper.convertValue()
),可能会使用现有的多态反序列化支持。这将取决于列命名的一些共性,所以我不知道它是否真实。
假设它正常工作,您需要一个具有与要使用的第一列的逻辑名匹配的属性的基类;然后具有类似匹配属性名称的子类型。
您可以在基类上使用@JsonTypeInfo
,并使用&#39; name&#39;作为类型id;并在子类上使用@JsonTypeName
,或使用@JsonSubTypes
注释从基类引用。
也就是说,使用通常的Jackson配置。
如果这不起作用,两阶段处理可能不是一个糟糕的选择。这将导致所有单元格值被读取为不同的对象,但只要它们不被保留(即,您只在内存中保留一行数据),短期垃圾通常对GC没有问题(长 - 垃圾是一种昂贵的垃圾。)