如何写入大JSON数据?

Aks*_*hay 6 python json

我一直在尝试将大量(> 800mb)数据写入JSON文件;我做了一些相当多的试验和错误来获得此代码:

def write_to_cube(data):
    with open('test.json') as file1:
        temp_data = json.load(file1)

    temp_data.update(data)

    file1.close()

    with open('test.json', 'w') as f:
        json.dump(temp_data, f)

        f.close()
Run Code Online (Sandbox Code Playgroud)

运行它只需调用该函数write_to_cube({"some_data" = data})

现在这段代码的问题是,对于少量数据来说速度很快,但是当test.json文件超过 800mb 时就会出现问题。当我尝试更新或添加数据时,需要很长时间。

我知道有外部库,例如simplejsonjsonpickle,我不太确定如何使用它们。

还有其他办法解决这个问题吗?

更新:

我不确定这怎么可能是重复的,其他文章没有提到编写或更新大型 JSON 文件,而是只提到了解析。

有没有一种内存高效且快速的方法来在 python 中加载大 json 文件?

在Python中读取相当大的json文件

上述任何一个都不能重复解决这个问题。他们没有谈论任何有关写作或更新的事情。

Zac*_*ung 2

我发现json-stream可能会有所帮助。虽然它确实提供了跳过输入 JSON 并将 Python 数据结构流式传输到输出 JSON 文件的机制,但如果没有 OP 的具体细节,很难说这是否能满足他们的需求。

为了看看它在处理大文件时是否确实具有内存优势,我模拟了这个基本的 JSON:

{
     "0": {"foo": "bar"},
     "1": {"foo": "bar"},
     "2": {"foo": "bar"},
     "3": {"foo": "bar"},
     ...
Run Code Online (Sandbox Code Playgroud)

最多 10M 个对象:

    ...
    "9999997": {"foo": "bar"},
    "9999998": {"foo": "bar"},
    "9999999": {"foo": "bar"},
}
Run Code Online (Sandbox Code Playgroud)

我已经提出将每个奇怪的对象更改为的要求{"foo": "BAR"}

{
    "0": {"foo": "bar"},
    "1": {"foo": "BAR"},
    "2": {"foo": "bar"},
    "3": {"foo": "BAR"},
    ...
    "9999997": {"foo": "BAR"},
    "9999998": {"foo": "bar"},
    "9999999": {"foo": "BAR"},
}
Run Code Online (Sandbox Code Playgroud)

我确信这比 OP 需要通过传递更新字典(我想象它有一个适度的“深度”结构)来完成的事情更琐碎。

我编写了脚本来处理一些测试文章的生成、读取和转换:

  • 产生

    @streamable_dict
    def yield_obj(n: int):
        for x in range(n):
            yield str(x), {"foo": "bar"}
    
    
    def gen_standard(n: int):
        with open(f"gen/{n}.json", "w") as f:
            obj = dict(list(yield_obj(n)))
            json.dump(obj, f, indent=1)
    
    
    def gen_stream(n: int):
        with open(f"gen/{n}.json", "w") as f:
            json.dump(yield_obj(n), f, indent=1)
    
    Run Code Online (Sandbox Code Playgroud)

    yield_obj()是一个迭代器,可以使用 实现,并在包装​​器的帮助下流dict(list(...))式传输到标准方法。json.dump()@streamable_dict

    制作三个测试文件:

    -rw-r--r--   1 zyoung  staff   2.9M Feb 23 17:24 100000.json
    -rw-r--r--   1 zyoung  staff    30M Feb 23 17:24 1000000.json
    -rw-r--r--   1 zyoung  staff   314M Feb 23 17:24 10000000.json
    
    Run Code Online (Sandbox Code Playgroud)
  • read,它只是加载并传递所有内容:

    def read_standard(fname: str):
        with open(fname) as f:
            for _ in json.load(f):
                pass
    
    
    def read_stream(fname: str):
        with open(fname) as f:
            for _ in json_stream.load(f):
                pass
    
    Run Code Online (Sandbox Code Playgroud)
  • 变换,它应用了我愚蠢的“每个奇数 BAR 都大写”:

    def transform_standard(fname: str):
        with open(fname) as f_in:
            data = json.load(f_in)
            for key, value in data.items():
                if int(key) % 2 == 1:
                    value["foo"] = "BAR"
            with open(out_name(fname), "w") as f_out:
                json.dump(data, f_out, indent=1)
    
    
    def transform_stream(fname: str):
        @streamable_dict
        def update(data):
            for key, value in data.items():
                value = json_stream.to_standard_types(value)
                if int(key) % 2 == 1:
                    value["foo"] = "BAR"
                yield key, value
    
        with open(fname) as f_in:
            data = json_stream.load(f_in)
            updated_data = update(data)
            with open(out_name(fname), "w") as f_out:
                json.dump(updated_data, f_out, indent=1)
    
    Run Code Online (Sandbox Code Playgroud)

    @streamable_dict再次使用将update()迭代器转换为可传递给标准方法的可流式“事物” json.dump()

完整的代码和运行程序都在这个 Gist中。

统计数据显示,json-stream测试 100_000、1_000_000 和 10_000_000 个对象时具有平坦的内存曲线。不过,阅读和转换确实需要更多时间:

产生

方法 项目 实数 用户 系统 内存 (MB)
标准 1e+05 0.19 0.17 0.01 45.84
标准 1e+06 2.00 1.93 0.06 372.97
标准 1e+07 21.67 20.46 1.03 3480.29
溪流 1e+05 0.18 0.15 0.00 7.28
溪流 1e+06 1.43 1.41 0.02 7.69
溪流 1e+07 14.41 14.07 0.20 7.58

方法 项目 实数 用户 系统 内存 (MB)
标准 1e+05 0.05 0.04 0.01 48.28
标准 1e+06 0.58 0.50 0.05 390.17
标准 1e+07 7.69 6.73 0.80 3875.81
溪流 1e+05 0.32 0.31 0.01 7.70
溪流 1e+06 2.96 2.94 0.02 7.69
溪流 1e+07 29.88 29.65 0.17 7.77

转换

方法 项目 实数 用户 系统 内存 (MB)
标准 1e+05 0.19 0.17 0.01 48.05
标准 1e+06 1.83 1.75 0.07 388.83
标准 1e+07 20.16 19.15 0.91 3875.49
溪流 1e+05 0.63 0.61 0.01 7.61
溪流 1e+06 6.06 6.02 0.03 7.92
溪流 1e+07 61.44 60.89 0.35 8.44