1

我的 JSON 文件中有以下数据:

{
    "first": {
        "name": "James",
        "age": 30
    },
    "second": {
        "name": "Max",
        "age": 30
    },
    "third": {
        "name": "Norah",
        "age": 30
    },
    "fourth": {
        "name": "Sam",
        "age": 30
    }
}

我想按如下方式打印顶级键和对象:

import json
import ijson

fname = "data.json"

with open(fname) as f:
    raw_data = f.read()

data = json.loads(raw_data)

for k in data.keys():
    print k, data[k]

输出:

second {u'age': 30, u'name': u'Max'}
fourth {u'age': 30, u'name': u'Sam'}
third {u'age': 30, u'name': u'Norah'}
first {u'age': 30, u'name': u'James'}

到目前为止,一切都很好。但是,如果我想为一个大文件做同样的事情,我将不得不在内存中读取它。这非常慢并且需要大量内存。

我想使用增量 JSON 解析器(ijson在这种情况下)来实现我之前描述的:

上面的代码取自:No access to top level elements with ijson?

with open(fname) as f:
    json_obj = ijson.items(f,'').next()  # '' loads everything as only one object.
    for (key, value) in json_obj.items():
        print key + " -> " + str(value)    

这也不合适,因为它还会读取内存中的整个文件。这并不是真正的增量。

如何在 Python 中对 JSON 文件的顶级键和相应对象进行增量解析?

4

3 回答 3

1

由于本质上 json 文件是文本文件,因此请考虑将顶层剥离为字符串。基本上,使用读取文件可迭代方法,将字符串与每一行连接起来,然后在字符串包含}}表示顶层结束的双括号时跳出循环。当然,双括号条件必须去掉空格和换行符。

toplevelstring = ''

with open('data.json') as f:    
    for line in f:
        if not '}}' in toplevelstring.replace('\n', '').replace('\s+',''):
            toplevelstring = toplevelstring + line
        else:
            break

data = json.loads(toplevelstring)

现在,如果您的较大的 json 包含在方括号或其他大括号中,仍然在例程之上运行,但添加下面的行以切出第一个字符,[以及在顶级的最后一个大括号之后的逗号和换行符的最后两个字符:

[{
    "first": {
        "name": "James",
        "age": 30
    },
    "second": {
        "name": "Max",
        "age": 30
    },
    "third": {
        "name": "Norah",
        "age": 30
    },
    "fourth": {
        "name": "Sam",
        "age": 30
    }
},
{
    "data1": {
        "id": "AAA",
        "type": 55
    },
    "data2": {
        "id": "BBB",
        "type": 1601
    },
    "data3": {
        "id": "CCC",
        "type": 817
    }
}]

...

toplevelstring = toplevelstring[1:-2]
data = json.loads(toplevelstring)
于 2016-04-22T01:46:54.000 回答
0

来自github 问题的回答[文件名已更改]

import ijson
from ijson.common import ObjectBuilder


def objects(file):
    key = '-'
    for prefix, event, value in ijson.parse(file):
        if prefix == '' and event == 'map_key':  # found new object at the root
            key = value  # mark the key value
            builder = ObjectBuilder()
        elif prefix.startswith(key):  # while at this key, build the object
            builder.event(event, value)
            if event == 'end_map':  # found the end of an object at the current key, yield
                yield key, builder.value


for key, value in objects(open('data.json', 'rb')):
    print(key, value)
于 2017-05-23T14:35:51.380 回答
0

从 2.6 版开始,ijson 附带了一个kvitems可以实现这一点的功能。

于 2021-02-14T12:57:45.183 回答