有没有内存高效且快速的方式加载大JSON文件?
我有一些500MB的json文件。如果我用简单的json.load()
一次性加载所有内容,会消耗很多内存。
有没有办法部分读取这个文件?如果它是一个文本文件,按行分隔的,我就可以逐行读取。我在寻找类似的办法。
11 个回答
问题不是每个文件太大,而是文件数量太多,导致它们在内存中累积。Python的垃圾回收机制应该没问题,除非你保留了一些不需要的引用。没有更多的信息,很难确切知道发生了什么,但你可以尝试以下几种方法:
将你的代码模块化。可以这样做:
for json_file in list_of_files: process_file(json_file)
如果你编写的
process_file()
函数不依赖于任何全局状态,也不改变任何全局状态,那么垃圾回收机制就能正常工作。在不同的进程中处理每个文件。不要一次性解析所有的JSON文件,而是写一个程序只解析一个文件,然后通过一个shell脚本或另一个Python进程使用
subprocess.Popen
调用你的脚本,逐个传入文件。这样虽然不太优雅,但如果其他方法都不奏效,这样可以确保你不会在处理下一个文件时保留上一个文件的旧数据。
希望这些建议对你有帮助。
这个问题有一个重复的帖子,里面的答案更好。可以看看这个链接:https://stackoverflow.com/a/10382359/1623645,它推荐了一个叫做ijson的工具。
更新:
我试了一下,发现ijson处理JSON的方式就像SAX处理XML一样。举个例子,你可以这样做:
import ijson
for prefix, the_type, value in ijson.parse(open(json_file_name)):
print(prefix, the_type, value)
这里的prefix
是JSON树中的一个用点分隔的索引(如果你的键名里有点,那会发生什么呢?我想这对JavaScript来说也不好...),theType
描述了一种类似SAX的事件,可能是'null', 'boolean', 'number', 'string', 'map_key', 'start_map', 'end_map', 'start_array', 'end_array'
中的一种,而value
是对象的值,如果the_type
是像开始/结束一个映射或数组这样的事件,那么value
就是None
。
这个项目有一些文档说明,但整体的文档不够。我不得不深入到ijson/common.py
里去找我想要的东西。
更新
可以看看其他回答里的建议。
2010年的原始回答,现在已经过时
简单来说:不可以。
要正确地把一个json文件分割开,需要对json对象的结构有很深入的了解。
不过,如果你掌握了这些知识,就可以创建一个类似文件的对象,来包装这个json文件,并把它分成合适的部分。
比如说,如果你知道你的json文件是一个包含多个对象的数组,你可以写一个生成器,来包装这个json文件,并返回数组的各个部分。
你需要对字符串内容进行一些解析,才能正确地分割json文件。
我不太清楚是什么生成了你的json内容。如果可以的话,我建议你生成几个小一点的文件,而不是一个超大的文件。