将大型JSON数组写入文件

12

我正在开发一个流程,很可能需要将非常大的JSON数组序列化到文件中。因此,将整个数组加载到内存中并直接转储到文件中是行不通的。我需要将每个单独的项流式传输到文件中以避免出现内存问题。

令人惊讶的是,我找不到任何这样做的示例。下面的代码片段是我拼凑在一起的东西。有更好的方法来做到这一点吗?

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("]")

1
而且你可能需要在以后从文件中加载数据,因此会遇到相同的问题。我想这就是为什么创建了换行符json格式的原因。 - roganjosh
1个回答

17

虽然您的代码是合理的,但它可以进一步改进。您有两个合理的选项和一个额外的建议。

您的选项是:

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

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

    读取JSON lines很简单,请参见Python中加载和解析具有多个JSON对象的JSON文件

  • 将数据包装在生成器和列表子类中,使json.dump()将其视为列表,然后迭代地编写数据。我将在下面概述这一点。请注意,您现在可能不得不相反地解决问题,使用Python再次读取JSON数据。

我的建议是不要在此处使用JSON。 JSON从未设计用于大规模数据集,它是面向更小有效载荷的Web交换格式。对于这种数据交换,有更好的格式可用。如果您无法偏离JSON,则至少使用JSON lines。

您可以使用生成器和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()函数在编码器生成数据块时写入文件,它永远不会在内存中保存所有输出。


有更好的格式来进行这种数据交换。您能指出一些更好的替代方案吗? - Adrian Martin
@AdrianMartin:如果没有更多关于使用情况的细节,我无法给出任何明智的建议。 - Martijn Pieters
谢谢 @MartijnPieters。我只是好奇。那我会提出一个适当的问题。 - Adrian Martin
嘿,这个回答有点老了,但我有一个关于它的问题。我正在寻找像这样的东西,可以将文件保存到磁盘而不是内存中。我尝试实现了一下,但我不确定我是否使用正确。 这是我的代码,https://hasteb.in/uyojamam.kotlin ,但这仍然保存在内存中,对吧? 理想情况下,我想保存program_json并在下次覆盖它,而不是拥有巨大的列表。 - Simeon Aleksov
1
@SimeonAleksov:抱歉,我没有时间直接帮忙。你可以尝试在Stack Overflow上发布一个问题吗? - Martijn Pieters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接