如何从一个文件中提取多个JSON对象?

2024-05-17 18:23:15 发布

您现在位置:Python中文网/ 问答频道 /正文

我对Json文件非常陌生。如果我有一个包含多个json对象的json文件,例如:

{"ID":"12345","Timestamp":"20140101", "Usefulness":"Yes",
 "Code":[{"event1":"A","result":"1"},…]}
{"ID":"1A35B","Timestamp":"20140102", "Usefulness":"No",
 "Code":[{"event1":"B","result":"1"},…]}
{"ID":"AA356","Timestamp":"20140103", "Usefulness":"No",
 "Code":[{"event1":"B","result":"0"},…]}
…

我想将所有“时间戳”和“有用性”提取到数据帧中:

    Timestamp    Usefulness
 0   20140101      Yes
 1   20140102      No
 2   20140103      No
 …

有人知道处理这些问题的一般方法吗


Tags: 文件对象noidjson时间coderesult
3条回答

使用json数组,格式如下:

[
{"ID":"12345","Timestamp":"20140101", "Usefulness":"Yes",
  "Code":[{"event1":"A","result":"1"},…]},
{"ID":"1A35B","Timestamp":"20140102", "Usefulness":"No",
  "Code":[{"event1":"B","result":"1"},…]},
{"ID":"AA356","Timestamp":"20140103", "Usefulness":"No",
  "Code":[{"event1":"B","result":"0"},…]},
...
]

然后将其导入python代码中

import json

with open('file.json') as json_file:

    data = json.load(json_file)

现在,数据的内容是一个数组,其中包含表示每个元素的字典

您可以轻松访问它,即:

data[0]["ID"]

因此,正如在几条注释中提到的,在数组中包含数据更简单,但随着数据集大小的增加,解决方案在效率方面不能很好地扩展。当您想要访问数组中的随机对象时,您确实应该只使用迭代器,否则,生成器就是最好的选择。下面我已经原型化了一个reader函数,它分别读取每个json对象并返回一个生成器

其基本思想是向读取器发送信号,让其在回车字符"\n"(或Windows的"\r\n")上拆分。Python可以通过^{}函数实现这一点

import json
def json_reader(filename):
    with open(filename) as f:
        for line in f:
            yield json.loads(line)

然而,这种方法只有在文件按原样编写时才真正起作用——每个对象由换行符分隔。下面我编写了一个writer示例,它将json对象数组分隔开来,并将每个对象保存在新行中

def json_writer(file, json_objects):
    with open(file, "w") as f:
        for jsonobj in json_objects:
            jsonstr = json.dumps(jsonobj)
            f.write(jsonstr + "\n")

您还可以对^{}和列表执行相同的操作:

...
    json_strs = [json.dumps(j) + "\n" for j in json_objects]
    f.writelines(json_strs)
...

如果您想附加数据而不是编写新文件,只需将open(file, "w")更改为open(file, "a")

最后,我发现这不仅有助于提高在文本编辑器中打开json文件时的可读性,而且还能更有效地使用内存

在这一点上,如果您在某个时候改变了主意,并且希望从读取器中得到一个列表,Python允许您在列表中放置一个生成器函数,并自动填充列表。换言之,只要写

lst = list(json_reader(file))

更新:我写了一个解决方案,不需要一次性读取整个文件。它对于stackoverflow答案来说太大了,但是可以在这里找到^{}

您可以使用json.JSONDecoder.raw_decode对“堆叠”JSON的任意大字符串进行解码(只要它们可以放入内存中)raw_decode一旦拥有有效的对象,就会停止,并返回最后一个不属于已解析对象的位置。它没有文档记录,但是您可以将这个位置传递回raw_decode,然后它再次从该位置开始解析。不幸的是,Python json模块不接受带有前缀空格的字符串。因此,我们需要搜索以查找文档中第一个非空白部分

from json import JSONDecoder, JSONDecodeError
import re

NOT_WHITESPACE = re.compile(r'[^\s]')

def decode_stacked(document, pos=0, decoder=JSONDecoder()):
    while True:
        match = NOT_WHITESPACE.search(document, pos)
        if not match:
            return
        pos = match.start()
        
        try:
            obj, pos = decoder.raw_decode(document, pos)
        except JSONDecodeError:
            # do something sensible if there's some error
            raise
        yield obj

s = """

{"a": 1}  


   [
1
,   
2
]


"""

for obj in decode_stacked(s):
    print(obj)

印刷品:

{'a': 1}
[1, 2]

相关问题 更多 >