我正在研究一个可能最终试图将非常大的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("]")
答案 0 :(得分:3)
虽然您的代码合理,但是可以对其进行改进。您有两个合理的选择,以及一个附加建议。
您的选择是:
不生成数组,而是生成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()
函数在编码器产生数据块时将其写入文件;它永远不会将所有输出保存在内存中。