JAVA – parsing巨大(超大)的JSON文件的最佳方法

我试图parsing一些巨大的JSON文件(如http://eu.battle.net/auction-data/258993a3c6b974ef3e6f22ea6f822720/auctions.json )使用gson库( http://code.google.com/p/google- gson / )在JAVA中。

我想知道什么是parsing这种大文件(大约80k行)最好的方法,如果你可能知道可以帮助我处理这个问题的好的API。

一些想法…

  1. 逐行阅读并删除JSON格式:但这是无稽之谈。
  2. 通过将这个文件分割成许多其他文件来减lessJSON文件:但是我没有find任何好的Java API。
  3. 直接使用这个文件作为非Sql数据库,保存该文件并将其用作我的数据库。

我真的很感激adices / help / messages / :-)谢谢。

你不需要切换到jackson。 Gson 2.1引入了一个新的TypeAdapter接口,允许混合树和stream式序列化和反序列化。

该API是高效和灵活的。 有关树和绑定模式组合的示例,请参阅Gson的Streaming文档 。 这比混合stream和树模式严格得多; 绑定你不浪费内存build立你的价值观的中间表示。

像jackson一样,Gson有APIrecursion地跳过不需要的值; Gson调用skipValue() 。

我会build议看一下Jackson Api ,将stream模式和树模型parsing选项结合起来非常简单:您可以通过stream式传输整个文件,然后将单个对象读入树结构。

作为一个例子 ,我们来看看下面的input:

 { "records": [ {"field1": "aaaaa", "bbbb": "ccccc"}, {"field2": "aaa", "bbb": "ccc"} ] , "special message": "hello, world!" } 

试想一下这些字段是稀疏的还是logging结构更复杂的。

以下片段说明如何使用stream和树模型parsing的组合来读取此文件。 每个单独的logging都是以树形结构读取的,但是文件从来没有完全读入内存,这使得使用最小的内存处理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()调用都会给出下一个parsing事件:开始对象,开始字段,开始数组,开始对象,…,结束对象,…,结束数组,…

jp.readValueAsTree()调用允许读取当前parsing位置(JSON对象或数组)到Jackson的通用JSON树模型中。 一旦你有了这个,你可以随机访问数据,不pipe文件中出现的顺序如何(在例子中field1和field2并不总是相同的顺序)。 jackson也支持映射到你自己的Java对象。 jp.skipChildren()方便:它允许跳过一个完整的对象树或一个数组,而无需运行其中包含的所有事件。