我有一个包含json对象数组的文件:
[ { “test1”:“abc” }, { “test2”:[1,2,3] } ]
我希望使用Jackson的JsonParser从这个文件中获取输入流,并且在每次调用.next()时,我希望它从数组中返回一个对象,直到它用完对象或失败。
这可能吗?
用例: 我有一个大型文件,其中json数组填充了大量具有不同模式的对象。我希望一次获得一个对象,以避免将所有内容加载到内存中。
编辑:
我完全忘了提及。我的输入是随着时间的推移而添加的字符串。它随着时间的推移逐渐积累json。我希望能够通过对象从字符串中删除已解析的对象来解析它。
但我想这没关系!只要jsonParser将索引返回到字符串中,我就可以手动执行此操作。
答案 0 :(得分:32)
是的,你可以使用ObjectMapper
实现这种部分流 - 部分 - 树模型处理风格:
ObjectMapper mapper = new ObjectMapper();
JsonParser parser = mapper.getFactory().createParser(new File(...));
if(parser.nextToken() != JsonToken.START_ARRAY) {
throw new IllegalStateException("Expected an array");
}
while(parser.nextToken() == JsonToken.START_OBJECT) {
// read everything from this START_OBJECT to the matching END_OBJECT
// and return it as a tree model ObjectNode
ObjectNode node = mapper.readTree(parser);
// do whatever you need to do with this object
}
parser.close();
答案 1 :(得分:12)
您要找的是Jackson Streaming API。这是一个使用Jackson Streaming API的代码片段,可以帮助您实现所需。
JsonFactory factory = new JsonFactory();
JsonParser parser = factory.createJsonParser(new File(yourPathToFile));
JsonToken token = parser.nextToken();
if (token == null) {
// return or throw exception
}
// the first token is supposed to be the start of array '['
if (!JsonToken.START_ARRAY.equals(token)) {
// return or throw exception
}
// iterate through the content of the array
while (true) {
token = parser.nextToken();
if (!JsonToken.START_OBJECT.equals(token)) {
break;
}
if (token == null) {
break;
}
// parse your objects by means of parser.getXxxValue() and/or other parser's methods
}
答案 2 :(得分:3)
这是一个基于Ian Roberts'回答。如果它嵌套到文档中,您还可以使用JsonPointer查找起始位置。这避免了自定义编码略微麻烦的流式令牌方法以到达起点。在这种情况下,basePath是" /",但它可以是JsonPointer理解的任何路径。
Path sourceFile = Paths.get("/path/to/my/file.json");
// Point the basePath to a starting point in the file
JsonPointer basePath = JsonPointer.compile("/");
ObjectMapper mapper = new ObjectMapper();
try (InputStream inputSource = Files.newInputStream(sourceFile);
JsonParser baseParser = mapper.getFactory().createParser(inputSource);
JsonParser filteredParser = new FilteringParserDelegate(baseParser,
new JsonPointerBasedFilter(basePath), false, false);) {
// Call nextToken once to initialize the filteredParser
JsonToken basePathToken = filteredParser.nextToken();
if (basePathToken != JsonToken.START_ARRAY) {
throw new IllegalStateException("Base path did not point to an array: found "
+ basePathToken);
}
while (filteredParser.nextToken() == JsonToken.START_OBJECT) {
// Parse each object inside of the array into a separate tree model
// to keep a fixed memory footprint when parsing files
// larger than the available memory
JsonNode nextNode = mapper.readTree(filteredParser);
// Consume/process the node for example:
JsonPointer fieldRelativePath = JsonPointer.compile("/test1");
JsonNode valueNode = nextNode.at(fieldRelativePath);
if (!valueNode.isValueNode()) {
throw new IllegalStateException("Did not find value at "
+ fieldRelativePath.toString()
+ " after setting base to " + basePath.toString());
}
System.out.println(valueNode.asText());
}
}
答案 3 :(得分:0)
此示例直接从流中读取自定义对象:
源是一个java.io.File
ObjectMapper mapper = new ObjectMapper();
JsonParser parser = mapper.getFactory().createParser( source );
if ( parser.nextToken() != JsonToken.START_ARRAY ) {
throw new Exception( "no array" );
}
while ( parser.nextToken() == JsonToken.START_OBJECT ) {
CustomObj custom = mapper.readValue( parser, CustomObj.class );
System.out.println( "" + custom );
}