Python 如何从一个文件中提取多个JSON对象?
我对Json文件非常陌生。如果我有一个包含多个json对象的json文件,例如:Python 如何从一个文件中提取多个JSON对象?,python,json,pandas,dataframe,parsing,Python,Json,Pandas,Dataframe,Parsing,我对Json文件非常陌生。如果我有一个包含多个json对象的json文件,例如: {“ID”:“12345”,“时间戳”:“20140101”,“有用性”:“是”, “代码”:[{“事件1”:“A”,“结果”:“1”},…]} {“ID”:“1A35B”,“时间戳”:“20140102”,“有用性”:“否”, “代码”:[{“事件1”:“B”,“结果”:“1”},…]} {“ID”:“AA356”,“时间戳”:“20140103”,“有用性”:“否”, “代码”:[{“event1”:“B”,“
{“ID”:“12345”,“时间戳”:“20140101”,“有用性”:“是”,
“代码”:[{“事件1”:“A”,“结果”:“1”},…]}
{“ID”:“1A35B”,“时间戳”:“20140102”,“有用性”:“否”,
“代码”:[{“事件1”:“B”,“结果”:“1”},…]}
{“ID”:“AA356”,“时间戳”:“20140103”,“有用性”:“否”,
“代码”:[{“event1”:“B”,“结果”:“0”},…]}
…
我想将所有“时间戳”和“有用性”提取到数据帧中:
时间戳有用性
0 20140101是
20140102号
2 20140103号
…
有人知道处理此类问题的一般方法吗?使用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\u decode
,然后它从该位置再次开始解析。不幸的是,Pythonjson
模块不接受带有前缀空格的字符串。因此,我们需要搜索以查找文档中第一个非空白部分
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]
根据@dunes的答案添加了流媒体支持:
重新导入
从json导入JSONDecoder,JSONDecodeError
NOT_WHITESPACE=re.compile(r“[^\s]”)
def stream_json(文件_obj,buf_size=1024,解码器=JSONDecoder()):
buf=“”
ex=无
尽管如此:
块=文件对象读取(大小)
如果不阻止:
打破
buf+=块
pos=0
尽管如此:
匹配=不包含空格。搜索(buf,pos)
如果不匹配:
打破
pos=match.start()
尝试:
obj,pos=解码器。原始解码(buf,pos)
除了JSONDecodeError作为e:
ex=e
打破
其他:
ex=无
产量目标
buf=buf[pos:]
如果ex不是无:
加薪
拥有一个包含所有json对象的json数组将非常容易。这很酷,但会阻止您将文件用作无穷无尽的流(例如,类似于日志的只追加文件数据),并消耗更多内存。@exa,这是真的,但如果您需要只追加此数据流的日志,也许您应该使用JSON以外的格式来传输信息,因为JSON需要所有数据结构的右括号,这意味着非无限非流格式,除了几件事之外,这个答案非常类似:它需要将整个文件读入内存,并使用JSONDecoder
的未记录功能。仅供参考:对于非空白字符有一个简单的转义:\S
。大写变量是小写变量的否定形式(因此\W=[^\W]
,\D=[^\D]
ecc)。如果文件具有单行多JSON文件,则这适用于AWS Lambda。。你能更详细地解释一下这是怎么回事吗?我无法理解raw_decode,也无法理解它如何理解有效的json何时开始或结束