如何使用“json”模块一次读入一个JSON对象?
我有一个多GB的JSON文件。 该文件由不超过几千个字符的JSON对象组成,但logging之间没有换行符。
使用Python 3和json
模块,我怎样才能从文件读入一个JSON对象到内存?
数据是纯文本文件。 这是一个类似logging的例子。 实际logging包含许多嵌套字典和列表。
以可读格式logging:
{ "results": { "__metadata": { "type": "DataServiceProviderDemo.Address" }, "Street": "NE 228th", "City": "Sammamish", "State": "WA", "ZipCode": "98074", "Country": "USA" } } }
实际格式。 新logging一个接一个地开始,没有任何中断。
{"results": { "__metadata": {"type": "DataServiceProviderDemo.Address"},"Street": "NE 228th","City": "Sammamish","State": "WA","ZipCode": "98074","Country": "USA" } } }{"results": { "__metadata": {"type": "DataServiceProviderDemo.Address"},"Street": "NE 228th","City": "Sammamish","State": "WA","ZipCode": "98074","Country": "USA" } } }{"results": { "__metadata": {"type": "DataServiceProviderDemo.Address"},"Street": "NE 228th","City": "Sammamish","State": "WA","ZipCode": "98074","Country": "USA" } } }
一般来说,将多个JSON对象放在一个文件中会使该文件无效,破坏JSON 。 也就是说,您仍然可以使用JSONDecoder.raw_decode()
方法以块的JSONDecoder.raw_decode()
parsing数据。
以下内容将在parsing器find它们时产生完整的对象:
from json import JSONDecoder from functools import partial def json_parse(fileobj, decoder=JSONDecoder(), buffersize=2048): buffer = '' for chunk in iter(partial(fileobj.read, buffersize), ''): buffer += chunk while buffer: try: result, index = decoder.raw_decode(buffer) yield result buffer = buffer[index:] except ValueError: # Not enough data to decode, read more break
这个函数将从缓冲区块中的给定文件对象中读取块,并使decoder
对象从缓冲区中parsing整个JSON对象。 每个parsing的对象都被发送给调用者。
像这样使用它:
with open('yourfilename', 'r') as infh: for data in json_parse(infh): # process object
只有当你的JSON对象被连续写入一个文件时,才能使用它,而没有换行符。 如果确实有换行符,并且每个JSON对象都被限制为一行,那么您就有一个JSON Lines文档 ,在这种情况下,您可以使用Python加载和parsing带有多个JSON对象的JSON文件 。
如果您的JSON文档包含对象列表,并且您想要一次读取一个对象,则可以使用迭代JSONparsing器ijson作为作业。 它只会在需要解码下一个对象时从文件中读取更多的内容。
请注意,您应该将其与YAJL库一起使用,否则您可能看不到任何性能提升。
也就是说,除非你的文件真的很大 ,否则将它完全读入内存然后用正常的JSON模块parsing它可能仍然是最好的select。
Martijn Pieters的解决scheme稍作修改,它将处理以空格分隔的JSONstring。
def json_parse(fileobj, decoder=json.JSONDecoder(), buffersize=2048, delimiters=None): remainder = '' for chunk in iter(functools.partial(fileobj.read, buffersize), ''): remainder += chunk while remainder: try: stripped = remainder.strip(delimiters) result, index = decoder.raw_decode(stripped) yield result remainder = stripped[index:] except ValueError: # Not enough data to decode, read more break
例如,如果data.txt
包含由空格分隔的JSONstring:
{"business_id": "1", "Accepts Credit Cards": true, "Price Range": 1, "type": "food"} {"business_id": "2", "Accepts Credit Cards": true, "Price Range": 2, "type": "cloth"} {"business_id": "3", "Accepts Credit Cards": false, "Price Range": 3, "type": "sports"}
然后
In [47]: list(json_parse(open('data'))) Out[47]: [{u'Accepts Credit Cards': True, u'Price Range': 1, u'business_id': u'1', u'type': u'food'}, {u'Accepts Credit Cards': True, u'Price Range': 2, u'business_id': u'2', u'type': u'cloth'}, {u'Accepts Credit Cards': False, u'Price Range': 3, u'business_id': u'3', u'type': u'sports'}]