Python 如何使用';json';一次读入一个JSON对象的模块?

Python 如何使用';json';一次读入一个JSON对象的模块?,python,json,Python,Json,我有一个千兆字节的JSON文件。该文件由JSON对象组成,每个对象不超过几千个字符,但记录之间没有换行符 使用Python3和json模块,如何一次从文件中读取一个json对象到内存中 数据位于纯文本文件中。下面是一个类似记录的示例。实际记录包含许多嵌套的字典和列表 以可读格式记录: { "results": { "__metadata": { "type": "DataServiceProviderDemo.Address" }, "

我有一个千兆字节的JSON文件。该文件由JSON对象组成,每个对象不超过几千个字符,但记录之间没有换行符

使用Python3和
json
模块,如何一次从文件中读取一个json对象到内存中

数据位于纯文本文件中。下面是一个类似记录的示例。实际记录包含许多嵌套的字典和列表

以可读格式记录:

{
    "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" } } }{"results": { "__metadata": {"type": "DataServiceProviderDemo.Address"},"Street": "NE 228th","City": "Sammamish","State": "WA","ZipCode": "98074","Country": "USA" } } }

如果您的JSON文档包含一个对象列表,并且您希望一次读取一个对象,那么您可以使用迭代JSON解析器来完成此任务。它只会在需要解码下一个对象时从文件中读取更多内容

请注意,您应该将它与库一起使用,否则您可能不会看到任何性能提高


也就是说,除非您的文件非常大,否则将其完全读入内存,然后使用普通的JSON模块对其进行解析可能仍然是最好的选择。

一般来说,将多个JSON对象放入一个文件会使该文件无效、损坏。也就是说,您仍然可以使用

以下内容将在解析器找到完整对象时生成它们:

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:].lstrip()
             except ValueError:
                 # Not enough data to decode, read more
                 break
此函数将从
buffersize
chunks中的给定文件对象中读取块,并让
decoder
对象从缓冲区解析整个JSON对象。每个被解析的对象都会被交给调用者

像这样使用它:

with open('yourfilename', 'r') as infh:
    for data in json_parse(infh):
        # process object

仅当您的JSON对象背靠背写入到文件中,且中间没有换行符时,才使用此选项。如果您有换行符,并且每个JSON对象仅限于一行,那么您可以使用,在这种情况下,您可以使用。

这里稍微修改一下,它将处理用空格分隔的JSON字符串

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
包含由空格分隔的JSON字符串:

{"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"}
然后


发布一个数据样本,至少有几个对象。你的意思是JSON文件是一个对象数组,你想懒洋洋地读取这些对象吗?你是否已经搜索了关于这个主题的其他文章,这里是关于堆栈溢出的?在这里的“相关”侧栏中至少列出了一个我可以看到的。那些帖子怎么没有针对你的具体情况?@poke我不知道你说的“懒散”是什么意思,但是的,我认为这正是我想要的。@MartijnPieters我能找到的其他帖子都没有针对同样的问题。你能分享你找到的解决方案的链接吗?这很有效,谢谢。是的,我处理的文件有背对背的JSON对象。同样在try/except中,我使用了“pass”而不是“break”。这是故意的吗?我无法让它工作。@user3281420:是的,
中断是故意的;它在
循环时中断
,因此我们继续从文件中读取下一个块。
中断
仅在当前缓冲区中没有要解码的JSON对象时才会触发。@user3281420:
通过
仅在缓冲区为空时有效,因为这是
while
循环的另一个终止条件。@RonanDejhero:添加
.strip()非常简单
调用
缓冲区
result,index=decoder.raw\u decode(buffer.strip())
删除空白,
buffer.strip('\n |')
删除一组显式字符。@user2441441:
data
是解码到Python对象的JSON数据。这取决于您解码的JSON对象以及如何从中获取键值对。
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'}]