1

我正在尝试逐个对象地流式传输 JSON 数组,但我需要将其作为原始 JSON 字符串导入。

给定一个输入数组,如下所示:

[
 {"object":1},
 {"object":2},
 ...
 {"object":n}
]

我正在尝试遍历字符串:

{"object":1}
{"object":2}
...
{"object":n}

我可以使用流 API 导航结构,以验证我是否遇到了一个对象,以及所有这些,但我认为我获取 String 的方式是理想的。

目前:

//[...]
//we have read a START_OBJECT token
JsonNode node = parser.readValueAsTree();
String jsonString = anObjectMapper.writeValueAsString(node);
//as opposed to  String jsonString = node.toString() ;
//[...]

我想整个 JsonNode 结构的构建涉及大量开销,如果我只是重新序列化,这是没有意义的,所以我正在寻找更好的解决方案。类似这样的东西是理想的:

//[...]
//we have read a START_OBJECT token
String jsonString = parser.readValueAsString()
//or parser.skipChildrenAsString()
//[...]

对象显然不像

{"object":1}

这就是为什么我不想浪费时间做毫无意义的节点构建。可能有一些理想的方法,涉及将内容映射到对象并使用它,但我无法做到这一点。我需要原始 JSON 字符串(一次一个对象)来处理现有代码。

任何建议或意见表示赞赏。谢谢!

编辑: parser.getText() 将当前标记作为文本返回(例如 START_OBJECT -> "{"),但不返回对象的其余部分。

Edit2:使用 Streaming API 的动机是一个一个地缓冲对象。实际的 json 文件可能会很大,每个对象在使用后都可以丢弃,所以我只需要迭代。

4

1 回答 1

4

没有办法避免 JSON 标记化(否则解析器将不知道对象从哪里开始和结束等),因此它总是会涉及某种程度的解析和生成。

但是您可以通过读取值来稍微减少开销,因为TokenBuffer它是 Jackson 的内部类型,具有最低的内存/性能开销(并且在需要缓冲时在内部使用):

TokenBuffer buf = parser.readValueAs(TokenBuffer.class);
// write straight from buffer if you have JsonGenerator
jgen.writeObject(buf);
// or, if you must, convert to byte[] or String
byte[] stuff = mapper.writeValueAsBytes();

但是,我们可以做得更好:如果您可以创建JsonGenerator输出,只需使用JsonGenerator.copyCurrentStructure(JsonParser);

jgen.copyCurrentStructure(jp); // points to END_OBJECT after copy

这将避免所有对象分配;虽然它需要解码 JSON,编码回 JSON,但它会相当有效。事实上,您甚至可以在 Jackson 支持的任何格式之间进行转码——读取 JSON,写入 XML/Smile/CSV/YAML/Avro。

于 2013-08-05T22:32:42.843 回答