当我尝试使用json.load()打开时,我有一个1.7 GB的JSON文件然后它会给出内存错误,怎么能在python中读取json文件?
我的JSON文件是包含特定键的大量对象。
编辑:如果它只是一个大的对象数组,并且事先知道对象的结构,那么就不需要使用我们可以逐行读取的工具。一行只包含数组的一个元素。我注意到这是json文件的存储方式,对我来说它只是>>>for line in open('file.json','r').readline():
... do something with(line)
答案 0 :(得分:10)
你想要一个增量的json解析器,比如yajl和它的一个python绑定。增量解析器从输入中尽可能少地读取,并在解码有意义的内容时调用回调。例如,仅从大型json文件中提取数字:
class ContentHandler(YajlContentHandler):
def yajl_number(self, ctx, val):
list_of_numbers.append(float(val))
parser = YajlParser(ContentHandler())
parser.parse(some_file)
有关详细信息,请参阅http://pykler.github.com/yajl-py/。
答案 1 :(得分:1)
我找到了另一个围绕 yajl 库的python包装器,它是ijson。
由于以下原因,它比yajl-py更适合我:
答案 2 :(得分:0)
当从本地磁盘访问大型数据文件时,我发现yajl(因此ijson)比模块json
慢得多。当与Cython一起使用时,这是一个声称比yajl / ijson(仍然慢于json
)表现更好的模块:
http://pietrobattiston.it/jsaone
正如作者所指出的,当通过网络接收文件时,性能可能优于json
,因为增量解析器可以更快地开始解析。
答案 3 :(得分:0)
对于简单用途(即遍历顶层数组中的项目),json-stream-parser看起来不错(我没有使用过)。它似乎是一个从234行纯Python重新实现的独立JSON解析器。
它不需要将JSON存储为“每行一个对象”或类似的东西。 JSON可以全是一行,也可以有换行符。
用法:
import sys
from json_stream_parser import load_iter
for obj in load_iter(sys.stdin):
print(obj)
答案 4 :(得分:0)
我已将Dask用于大型遥测JSON-Lines文件(以换行符分隔)...
Dask的好处是可以为您完成很多工作。
有了它,您可以读取,处理和写入磁盘,而无需全部读取到内存中。
Dask还将为您并行化并使用多个内核(线程)...
有关Dask袋的更多信息,请点击此处:
https://examples.dask.org/bag.html
import ujson as json #ujson for speed and handling NaNs which are not covered by JSON spec
import dask.bag as db
def update_dict(d):
d.update({'new_key':'new_value', 'a':1, 'b':2, 'c':0})
d['c'] = d['a'] + d['b']
return d
def read_jsonl(filepaths):
"""Read's a JSON-L file with a Dask Bag
:param filepaths: list of filepath strings OR a string with wildcard
:returns: a dask bag of dictionaries, each dict a JSON object
"""
return db.read_text(filepaths).map(json.loads)
filepaths = ['file1.jsonl.gz','file2.jsonl.gz']
#OR
filepaths = 'file*.jsonl.gz' #wildcard to match multiple files
#(optional) if you want Dask to use multiple processes instead of threads
# from dask.distributed import Client, progress
# client = Client(threads_per_worker=1, n_workers=6) #6 workers for 6 cores
# print(client)
#define bag containing our data with the JSON parser
dask_bag = read_jsonl(filepaths)
#modify our data
#note, this doesn't execute, it just adds it to a queue of tasks
dask_bag.map(update_dict)
#(optional) if you're only reading one huge file but want to split the data into multiple files you can use repartition on the bag
# dask_bag = dask_bag.repartition(10)
#write our modified data back to disk, this is when Dask actually performs execution
dask_bag.map(json.dumps).to_textfiles('file_mod*.jsonl.gz') #dask will automatically apply compression if you use .gz