我建议看看Jackson Api,结合流式处理和树模型解析选项非常容易:您可以以流式处理的方式将文件作为一个整体移动,然后将单个对象读取到树结构中。
例如,让我们采用以下输入:
{
"records": [
{"field1": "aaaaa", "bbbb": "ccccc"},
{"field2": "aaa", "bbb": "ccc"}
] ,
"special message": "hello, world!"
}
想象一下,字段是稀疏的,或者记录具有更复杂的结构。
以下代码段说明了如何使用流和树模型分析的组合来读取此文件。每个单独的记录都以树结构读取,但文件永远不会完整地读入内存中,因此可以在使用最小内存的同时处理大小为千兆字节的 JSON 文件。
import org.codehaus.jackson.map.*;
import org.codehaus.jackson.*;
import java.io.File;
public class ParseJsonSample {
public static void main(String[] args) throws Exception {
JsonFactory f = new MappingJsonFactory();
JsonParser jp = f.createJsonParser(new File(args[0]));
JsonToken current;
current = jp.nextToken();
if (current != JsonToken.START_OBJECT) {
System.out.println("Error: root should be object: quiting.");
return;
}
while (jp.nextToken() != JsonToken.END_OBJECT) {
String fieldName = jp.getCurrentName();
// move from field name to field value
current = jp.nextToken();
if (fieldName.equals("records")) {
if (current == JsonToken.START_ARRAY) {
// For each of the records in the array
while (jp.nextToken() != JsonToken.END_ARRAY) {
// read the record into a tree model,
// this moves the parsing position to the end of it
JsonNode node = jp.readValueAsTree();
// And now we have random access to everything in the object
System.out.println("field1: " + node.get("field1").getValueAsText());
System.out.println("field2: " + node.get("field2").getValueAsText());
}
} else {
System.out.println("Error: records should be an array: skipping.");
jp.skipChildren();
}
} else {
System.out.println("Unprocessed property: " + fieldName);
jp.skipChildren();
}
}
}
}
正如您可以猜到的,nextToken() 调用每次都会给出下一个解析事件:start object, start field, start array, start object, ..., end object, ..., end array, ...
该调用允许将当前解析位置(JSON 对象或数组)的内容读取到 Jackson 的通用 JSON 树模型中。完成此操作后,您可以随机访问数据,而不管内容在文件中的显示顺序如何(在示例中,field1 和 field2 并不总是以相同的顺序)。Jackson 也支持映射到你自己的 Java 对象。jp.skipChildren() 很方便:它允许跳过一个完整的对象树或数组,而不必自己运行其中包含的所有事件。jp.readValueAsTree()