使用Python的ijson读取包含多个JSON对象的大型JSON文件

15

我正在尝试使用ijson库解析一个大约100MB的JSON文件,该库可以高效地与文件进行交互。然而,在编写如下代码后,

with open(filename, 'r') as f:
    parser = ijson.parse(f)
    for prefix, event, value in parser:
        if prefix == "name":
            print(value)

我发现代码只解析了文件的第一行而没有解析其他行!

这是我的json文件的一部分内容:

{"name":"accelerator_pedal_position","value":0,"timestamp":1364323939.012000}
{"name":"engine_speed","value":772,"timestamp":1364323939.027000}
{"name":"vehicle_speed","value":0,"timestamp":1364323939.029000}
{"name":"accelerator_pedal_position","value":0,"timestamp":1364323939.035000}

我认为ijson仅解析一个JSON对象。

请问有人可以建议如何解决这个问题吗?


可能是 https://dev59.com/lGgv5IYBdhLWcg3wSe0f 的重复问题。 - ErikR
嗯,你提供的那一块看起来像是一组JSON。也就是说,你需要逐行读取并单独解析每一个JSON。 - user3159253
顺便提一下,由于每行都很短,您不需要使用ijson,可以使用json.loads() - user3159253
2个回答

13

由于提供的代码块看起来更像是一组独立的JSON行,因此应相应地进行解析:

# each JSON is small, there's no need in iterative processing
import json 
with open(filename, 'r') as f:
    for line in f:
        data = json.loads(line)
        # data[u'name'], data[u'engine_speed'], data[u'timestamp'] now
        # contain correspoding values

1
谢谢您的回答,我想知道这个程序是否只会加载一行而不是整个文件到内存中?如果它能够逐行加载,那就很棒了。 - Boubouh Karim
当使用 for line in f: 时,会一次读取一行。请参考 https://dev59.com/XGQm5IYBdhLWcg3w6Car。 - user3159253
我该如何在ijson中处理自定义的编码和解码?我可以使用json和cls=参数轻松地完成此操作,那么在ijson中该如何实现呢?有什么链接吗?谢谢! - gilgamash

11

很不幸,ijson库(截至2018年3月的v2.3版本)不能处理解析多个JSON对象。它只能处理一个整体对象,如果您尝试解析第二个对象,您将收到以下错误:"ijson.common.JSONError: Additional data"。请参见此处的错误报告:

这是一个很大的限制。但是,只要每个JSON对象后都有换行符(换行字符),您就可以独立地逐行解析每个对象,就像这样:

import io
import ijson

with open(filename, encoding="UTF-8") as json_file:
    cursor = 0
    for line_number, line in enumerate(json_file):
        print ("Processing line", line_number + 1,"at cursor index:", cursor)
        line_as_file = io.StringIO(line)
        # Use a new parser for each line
        json_parser = ijson.parse(line_as_file)
        for prefix, type, value in json_parser:
            print ("prefix=",prefix, "type=",type, "value=",value)
        cursor += len(line)

您仍在流式传输文件,而不是完全加载到内存中,因此可以处理大型JSON文件。 它还使用来自如何跳转至巨大文本文件中的特定行?的逐行流技术,并使用在Python循环中访问索引enumerate()函数。


谢谢 @Mr-IDE。我终于能够使用 ijson 从我的 5.5Gb 数据集中读取一些东西了。成功偷看到了一些信息,例如 dataID、status、values 和 location。问题是,如何一次性读取所有需要的信息,比如“location”? - Azam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接