我正在编写一个程序,它要求我生成一个非常大的json
文件。我知道传统的方法是使用json.dump()
转储字典列表,但是列表太大了,甚至总内存+交换空间也无法在转储之前保留它。无论如何都要将它流式传输到json
文件,即将数据逐步写入json
文件?
答案 0 :(得分:14)
我知道这已经晚了一年,但问题仍然存在,我很惊讶json.iterencode()未被提及。
本例中iterencode
的潜在问题是,您希望使用生成器对大型数据集进行迭代处理,而json编码不会序列化生成器。
解决这个问题的方法是子类列表类型并覆盖__iter__
魔术方法,以便您可以生成生成器的输出。
以下是此列表子类的示例。
class StreamArray(list):
"""
Converts a generator into a list object that can be json serialisable
while still retaining the iterative nature of a generator.
IE. It converts it to a list without having to exhaust the generator
and keep it's contents in memory.
"""
def __init__(self, generator):
self.generator = generator
self._len = 1
def __iter__(self):
self._len = 0
for item in self.generator:
yield item
self._len += 1
def __len__(self):
"""
Json parser looks for a this method to confirm whether or not it can
be parsed
"""
return self._len
从这里开始使用非常简单。获取生成器句柄,将其传递到StreamArray
类,将流数组对象传递到iterencode()
并迭代块。这些块将是json格式输出,可以直接写入文件。
使用示例:
#Function that will iteratively generate a large set of data.
def large_list_generator_func():
for i in xrange(5):
chunk = {'hello_world': i}
print 'Yielding chunk: ', chunk
yield chunk
#Write the contents to file:
with open('/tmp/streamed_write.json', 'w') as outfile:
large_generator_handle = large_list_generator_func()
stream_array = StreamArray(large_generator_handle)
for chunk in json.JSONEncoder().iterencode(stream_array):
print 'Writing chunk: ', chunk
outfile.write(chunk)
显示产量和写入的输出连续发生。
Yielding chunk: {'hello_world': 0}
Writing chunk: [
Writing chunk: {
Writing chunk: "hello_world"
Writing chunk: :
Writing chunk: 0
Writing chunk: }
Yielding chunk: {'hello_world': 1}
Writing chunk: ,
Writing chunk: {
Writing chunk: "hello_world"
Writing chunk: :
Writing chunk: 1
Writing chunk: }
答案 1 :(得分:2)
遗憾的是json
库没有任何增量写入功能,因此无法做到你想要的。
这显然是非常大文件 - 其他一些表示会更合适吗?
否则,我可以做的最好建议是将每个列表条目转储到内存中结构,并使用必要的分隔符(开头为[
,条目之间为],[
和{{}将其写出来1}}在最后)尝试构建您需要的JSON。
如果格式化很重要,你应该知道程序写入的包装器测试会破坏正确的缩进,但缩进仅适用于人类,所以它不应该对JSON结构的语义产生任何影响。
答案 2 :(得分:0)
您还可以假设您有一个可迭代的it
,并且希望将其作为大的JSON记录数组写到文件句柄fh
中,然后执行以下操作,我认为这是最多的简单的方法:
def write_json_iter(it, fh):
print("[", file=fh)
for n, rec in enumerate(it):
if n > 0:
print(",", file=fh)
json.dump(rec, fh)
print("]", file=fh)