小编典典

如何在Python中从文件/流懒惰地读取多个JSON值?

json

我想一次从Python的文件/流中读取多个JSON对象。不幸的是json.load()刚刚.read()s,至文件结束-;
似乎没有任何方法可以使用它来读取单个对象或延迟迭代这些对象。

有什么办法吗?使用标准库将是理想的选择,但是如果有第三方库,我会改用它。

目前,我将每个对象放在单独的行上并使用json.loads(f.readline()),但我真的不希望这样做。

使用范例

example.py

import my_json as json
import sys

for o in json.iterload(sys.stdin):
    print("Working on a", type(o))

in.txt

{"foo": ["bar", "baz"]} 1 2 [] 4 5 6

示例会话

$ python3.2 example.py < in.txt
Working on a dict
Working on a int
Working on a int
Working on a list
Working on a int
Working on a int
Working on a int

阅读 272

收藏
2020-07-27

共1个答案

小编典典

这是一个非常简单的解决方案。秘诀是尝试,失败并使用异常中的信息正确解析。唯一的限制是该文件必须可搜索。

def stream_read_json(fn):
    import json
    start_pos = 0
    with open(fn, 'r') as f:
        while True:
            try:
                obj = json.load(f)
                yield obj
                return
            except json.JSONDecodeError as e:
                f.seek(start_pos)
                json_str = f.read(e.pos)
                obj = json.loads(json_str)
                start_pos += e.pos
                yield obj

编辑:只是注意到这仅适用于Python> = 3.5。对于更早的版本,失败返回ValueError,并且您必须从字符串中解析出位置,例如

def stream_read_json(fn):
    import json
    import re
    start_pos = 0
    with open(fn, 'r') as f:
        while True:
            try:
                obj = json.load(f)
                yield obj
                return
            except ValueError as e:
                f.seek(start_pos)
                end_pos = int(re.match('Extra data: line \d+ column \d+ .*\(char (\d+).*\)',
                                    e.args[0]).groups()[0])
                json_str = f.read(end_pos)
                obj = json.loads(json_str)
                start_pos += end_pos
                yield obj
2020-07-27