如何使用“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'}]