python - 如何在 Python 中有效地解析大型 JSON 文件?

标签 python json

我有一个包含 JSON 对象数组的文件。该文件超过 1GB,因此我无法一次将其全部加载到内存中。我需要解析每个单独的对象。我尝试使用 ijson,但这会将整个数组作为一个对象加载,有效地执行与简单的 json.load() 相同的操作。

还有其他方法吗?

编辑:没关系,只需使用 ijson.items() 并将前缀参数设置为 "item"

最佳答案

您可以解析一次 JSON 文件以找到每个一级分隔符的位置,即作为顶级对象一部分的逗号,然后将文件分成这些位置指示的部分。例如:

{"a": [1, 2, 3], "b": "Hello, World!", "c": {"d": 4, "e": 5}}
        ^      ^            ^        ^             ^
        |      |            |        |             |
     level-2   |         quoted      |          level-2
               |                     |
            level-1               level-1

这里我们想要找到 level-1 逗号,它分隔顶级对象包含的对象。我们可以使用一个生成器来解析 JSON 流并跟踪进入和退出嵌套对象的过程。当它遇到未被引用的 1 级逗号时,它会产生相应的位置:

def find_sep_pos(stream, *, sep=','):
    level = 0
    quoted = False  # handling strings in the json
    backslash = False  # handling quoted quotes
    for pos, char in enumerate(stream):
        if backslash:
            backslash = False
        elif char in '{[':
            level += 1
        elif char in ']}':
            level -= 1
        elif char == '"':
            quoted = not quoted
        elif char == '\\':
            backslash = True
        elif char == sep and not quoted and level == 1:
            yield pos

用于上面的示例数据,这将给出 list(find_sep_pos(example)) == [15, 37]

然后我们可以将文件分成对应于分隔符位置的部分,并通过json.loads 单独加载每个部分:

import itertools as it
import json

with open('example.json') as fh:
    # Iterating over `fh` yields lines, so we chain them in order to get characters.
    sep_pos = tuple(find_sep_pos(it.chain.from_iterable(fh)))
    fh.seek(0)  # reset to the beginning of the file
    stream = it.chain.from_iterable(fh)
    opening_bracket = next(stream)
    closing_bracket = dict(('{}', '[]'))[opening_bracket]
    offset = 1  # the bracket we just consumed adds an offset of 1
    for pos in sep_pos:
        json_str = (
            opening_bracket
            + ''.join(it.islice(stream, pos - offset))
            + closing_bracket
        )
        obj = json.loads(json_str)  # this is your object
        next(stream)  # step over the separator
        offset = pos + 1  # adjust where we are in the stream right now
        print(obj)
    # The last object still remains in the stream, so we load it here.
    obj = json.loads(opening_bracket + ''.join(stream))
    print(obj)

关于python - 如何在 Python 中有效地解析大型 JSON 文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60695099/

相关文章:

python - 大数据集上 numpy polyfit 的解读

python - 具有不同时间步长的 RNN 的 Keras 掩蔽

ruby-on-rails - 具有自定义嵌套属性名称的 Rails 4 强参数

json - Groovy JsonSlurper 涉及 JSON 中逗号的问题

java - Jackson - 在没有注释的情况下在运行时修改属性

python - 如何将参数传递给 animation.FuncAnimation()?

python - 运行开发服务器时在 Django 应用程序上列出超出范围的索引

python - 在 Python 的属性上使用装饰器处理异常

c# - 使用MySql内连接在谷歌饼图上显示数据

arrays - 在 swift 中初始化 json api 后出现错误