【问题标题】:Writing a Large JSON Array To File将大型 JSON 数组写入文件
【发布时间】:2019-02-07 19:03:29
【问题描述】:

我正在研究一个最终可能会尝试将非常大的 json 数组序列化到文件的过程。因此,将整个数组加载到内存中并仅转储到文件是行不通的。我需要将各个项目流式传输到文件以避免内存不足问题。

令人惊讶的是,我找不到任何这样做的例子。下面的代码 sn-p 是我拼凑起来的。有没有更好的方法来做到这一点?

first_item = True
with open('big_json_array.json', 'w') as out:
     out.write('[')
     for item in some_very_big_iterator:
          if first_item:
               out.write(json.dumps(item))
               first_item = False
          else:
               out.write("," + json.dumps(item))
     out.write("]")

【问题讨论】:

  • 并且大概您需要在以后从文件中加载数据,因此会遇到同样的问题。我想这就是创建换行 json 格式的原因

标签: python json serialization


【解决方案1】:

虽然您的代码是合理的,但可以对其进行改进。你有两个合理的选择,还有一个额外的建议。

您的选择是:

  • 不生成数组,而是生成JSON Lines 输出。对于生成器中的每个项目,这会将一个有效的 JSON 文档不带换行符写入文件,然后是换行符。这很容易使用默认的json.dump(item, out) 配置生成,然后是 `out.write('\n')。您最终会得到一个文件,每行都有一个单独的 JSON 文档。

    优点是您在写入或再次读取数据时不必担心内存问题,否则以后从文件中读取数据时会遇到更大的问题; json 模块不能迭代加载数据,除非手动跳过初始的 [ 和逗号。

    读取 JSON 行很简单,见Loading and parsing a JSON file with multiple JSON objects in Python

  • 将数据包装在生成器和列表子类中,使json.dump() 接受它作为列表,然后迭代地写入数据。我将在下面概述这一点。考虑到您现在可能需要反向解决问题,读取再次使用 Python 的 JSON 数据。

我的建议是在这里不要使用 JSON。 JSON 从来都不是为大规模数据集设计的,它是一种针对更小负载的 Web 交换格式。这种数据交换有更好的格式。如果你不能偏离 JSON,那么至少使用 JSON 行。

您可以使用生成器和 list 子类迭代地编写 JSON 数组,以欺骗 json 库接受它作为列表:

class IteratorAsList(list):
    def __init__(self, it):
        self.it = it
    def __iter__(self):
        return self.it
    def __len__(self):
        return 1

with open('big_json_array.json', 'w') as out:
    json.dump(IteratorAsList(some_very_big_iterator), out)

IteratorAsList 类满足json 编码器进行的两个测试:对象是列表或其子类,并且它的长度大于 0;当满足这些条件时,它将遍历列表(使用__iter__)并对每个对象进行编码。

json.dump() 函数随后在编码器产生数据块时写入文件;它永远不会将所有输出保存在内存中。

【讨论】:

  • 这种数据交换有更好的格式。您愿意指出一些更好的选择吗?
  • @AdrianMartin:如果没有更多关于用例的详细信息,我无法给出任何明智的建议。
  • 感谢@MartijnPieters。我只是好奇而已。那么,我会问一个适当的问题。
  • 嘿,有点旧的答案,但我有一个关于这个的问题,我正在寻找这样的东西,保存到文件而不保存到内存。我试图实现,但我不确定我是否正确使用它。这是我的代码,hasteb.in/uyojamam.kotlin,但这仍然会保存到内存中,对吧?|理想情况下,我想保存 program_json 并在下次覆盖它,而不需要大量列表。
  • @SimeonAleksov:抱歉,我没有时间直接提供帮助。您可以尝试在 Stack Overflow 上发布有关它的问题?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-24
  • 1970-01-01
相关资源
最近更新 更多