首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >JAVA -解析巨大(超大) JSON文件的最佳方法

JAVA -解析巨大(超大) JSON文件的最佳方法
EN

Stack Overflow用户
提问于 2012-02-22 06:55:33
回答 3查看 125.3K关注 0票数 61

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

我想知道解析这类大文件(大约80k行)的最佳方法是什么,如果您可能知道一个好的API,可以帮助我处理这个文件。

一些想法..。

  1. 逐行阅读并去掉JSON格式:但这是胡说八道。
  2. 通过将JSON文件拆分成许多其他文件来减少JSON文件:但我没有找到任何良好的Java。
  3. 将该文件直接用作nonSql数据库,保存该文件并将其用作我的数据库。

我非常感谢您的建议/帮助/留言/ :-)谢谢。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-02-27 05:03:49

你不需要换到杰克逊。GSON2.1引入了一个新的TypeAdapter接口,它允许混合树以及流序列化和反序列化。

该API是高效和灵活的。有关合并树和绑定模式的示例,请参见。这比混合流模式和树模式要好得多;通过绑定,您不会浪费内存,为您的值构建中间表示。

和Jackson一样,Gson有递归跳过不想要的值的API;Gson调用这个skipValue()

票数 49
EN

Stack Overflow用户

发布于 2012-02-22 07:10:15

我建议查看一下杰克逊·阿皮 --结合流和树模型解析选项是非常容易的:您可以以流的方式在整个文件中移动,然后将单个对象读取到树结构中。

作为一个示例,让我们接受以下输入:

代码语言:javascript
运行
复制
{ 
  "records": [ 
    {"field1": "aaaaa", "bbbb": "ccccc"}, 
    {"field2": "aaa", "bbb": "ccc"} 
  ] ,
  "special message": "hello, world!" 
}

想象一下,字段很稀疏,或者记录具有更复杂的结构。

下面的片段说明了如何使用流和树模型解析的组合来读取该文件。每个单独的记录都是在树结构中读取的,但是文件永远不会被读取到内存中,这样就可以在使用最小内存的同时处理JSON文件的千兆字节。

代码语言:javascript
运行
复制
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字段、start array、start object、.、end object、.

jp.readValueAsTree()调用允许将当前解析位置的JSON对象或数组读入杰克逊的通用JSON树模型。有了这个之后,就可以随意地访问数据,而不管文件中出现的东西的顺序如何(在示例中,field1和field2并不总是按照相同的顺序)。Jackson也支持映射到您自己的Java对象上。jp.skipChildren()非常方便:它允许跳过完整的对象树或数组,而不必自己运行其中包含的所有事件。

票数 49
EN

Stack Overflow用户

发布于 2019-05-06 14:40:38

声明流映射(DSM)库允许您定义JSON或XML数据与POJO之间的映射。因此,您不需要编写自定义解析器。İt支持强大的脚本(Javascript、groovy、JEXL)。您可以在阅读时过滤和转换数据。在读取数据时,可以调用部分数据操作的函数。DSM以流的形式读取数据,因此它使用非常低的内存。

例如,

代码语言:javascript
运行
复制
{
    "company": {
         ....
        "staff": [
            {
                "firstname": "yong",
                "lastname": "mook kim",
                "nickname": "mkyong",
                "salary": "100000"
            },
            {
                "firstname": "low",
                "lastname": "yin fong",
                "nickname": "fong fong",
                "salary": "200000"
            }
        ]
    }
}

假设上面的片段是庞大而复杂的JSON数据的一部分。我们只想得到比 10000更高的东西。

首先,我们必须按以下方式定义映射定义。正如您所看到的,它只是一个yaml文件,包含POJO字段和JSON数据字段之间的映射。

代码语言:javascript
运行
复制
result:
      type: object     # result is map or a object.
      path: /.+staff  # path is regex. its match with /company/staff
      function: processStuff  # call processStuff function when /company/stuff tag is closed
      filter: self.data.salary>10000   # any expression is valid in JavaScript, Groovy or JEXL
      fields:
        name:  
          path: firstname
        sureName:
          path: lastname
        userName:
          path: nickname
        salary: long

为流程人员创建FunctionExecutor。

代码语言:javascript
运行
复制
FunctionExecutor processStuff=new FunctionExecutor(){

            @Override
            public void execute(Params params) {

                // directly serialize Stuff class
                //Stuff stuff=params.getCurrentNode().toObject(Stuff.class);

                Map<String,Object> stuff= (Map<String,Object>)params.getCurrentNode().toObject();
                System.out.println(stuff);
                // process stuff ; save to db. call service etc.
            }
        };

使用DSM处理JSON

代码语言:javascript
运行
复制
     DSMBuilder builder = new DSMBuilder(new File("path/to/mapping.yaml")).setType(DSMBuilder.TYPE.XML);

       // register processStuff Function
        builder.registerFunction("processStuff",processStuff);

        DSM dsm= builder.create();
        Object object =  dsm.toObject(xmlContent);

输出:(仅包括薪资高于10000的内容)

代码语言:javascript
运行
复制
{firstName=low, lastName=yin fong, nickName=fong fong, salary=200000}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9390368

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档