如何从一个文件中提取多个 JSON 对象?
How to extract multiple JSON objects from one file?
我对 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" 提取到一个数据框中:
Timestamp Usefulness
0 20140101 Yes
1 20140102 No
2 20140103 No
…
有谁知道处理此类问题的一般方法吗?
使用 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 对象和 returns 一个生成器。
基本思想是指示 reader 在回车符 "\n"
上拆分(或 "\r\n"
表示 Windows)。 Python 可以用 file.readline()
函数做到这一点。
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")
您也可以使用 file.writelines()
和列表理解来执行相同的操作:
...
json_strs = [json.dumps(j) + "\n" for j in json_objects]
f.writelines(json_strs)
...
如果您想附加数据而不是写入新文件,只需将 open(file, "w")
更改为 open(file, "a")
。
最后我发现这不仅对我尝试在文本编辑器中打开 json 文件时的可读性有很大帮助,而且对更有效地使用内存也有很大帮助。
关于这一点,如果您在某个时候改变主意并且想要一个 reader 之外的列表,Python 允许您将生成器函数放在列表中并填充列表自动地。也就是说,只要写
lst = list(json_reader(file))
更新:我写了一个不需要一次读取整个文件的解决方案。它对于 Whosebug 的答案来说太大了,但可以在这里找到 jsonstream
.
您可以使用 json.JSONDecoder.raw_decode
来解码任意大的“堆叠”字符串 JSON(只要它们可以放入内存中)。 raw_decode
一旦它有一个有效的对象就停止,returns 最后一个位置不是解析对象的一部分。它没有记录,但您可以将此位置传回 raw_decode
并从该位置再次开始解析。不幸的是,Python json
模块不接受带有前缀空格的字符串。所以我们需要搜索以找到文档的第一个 none-空白部分。
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 的回答添加了流媒体支持:
import re
from json import JSONDecoder, JSONDecodeError
NOT_WHITESPACE = re.compile(r"[^\s]")
def stream_json(file_obj, buf_size=1024, decoder=JSONDecoder()):
buf = ""
ex = None
while True:
block = file_obj.read(buf_size)
if not block:
break
buf += block
pos = 0
while True:
match = NOT_WHITESPACE.search(buf, pos)
if not match:
break
pos = match.start()
try:
obj, pos = decoder.raw_decode(buf, pos)
except JSONDecodeError as e:
ex = e
break
else:
ex = None
yield obj
buf = buf[pos:]
if ex is not None:
raise ex
我对 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" 提取到一个数据框中:
Timestamp Usefulness
0 20140101 Yes
1 20140102 No
2 20140103 No
…
有谁知道处理此类问题的一般方法吗?
使用 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 对象和 returns 一个生成器。
基本思想是指示 reader 在回车符 "\n"
上拆分(或 "\r\n"
表示 Windows)。 Python 可以用 file.readline()
函数做到这一点。
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")
您也可以使用 file.writelines()
和列表理解来执行相同的操作:
...
json_strs = [json.dumps(j) + "\n" for j in json_objects]
f.writelines(json_strs)
...
如果您想附加数据而不是写入新文件,只需将 open(file, "w")
更改为 open(file, "a")
。
最后我发现这不仅对我尝试在文本编辑器中打开 json 文件时的可读性有很大帮助,而且对更有效地使用内存也有很大帮助。
关于这一点,如果您在某个时候改变主意并且想要一个 reader 之外的列表,Python 允许您将生成器函数放在列表中并填充列表自动地。也就是说,只要写
lst = list(json_reader(file))
更新:我写了一个不需要一次读取整个文件的解决方案。它对于 Whosebug 的答案来说太大了,但可以在这里找到 jsonstream
.
您可以使用 json.JSONDecoder.raw_decode
来解码任意大的“堆叠”字符串 JSON(只要它们可以放入内存中)。 raw_decode
一旦它有一个有效的对象就停止,returns 最后一个位置不是解析对象的一部分。它没有记录,但您可以将此位置传回 raw_decode
并从该位置再次开始解析。不幸的是,Python json
模块不接受带有前缀空格的字符串。所以我们需要搜索以找到文档的第一个 none-空白部分。
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 的回答添加了流媒体支持:
import re
from json import JSONDecoder, JSONDecodeError
NOT_WHITESPACE = re.compile(r"[^\s]")
def stream_json(file_obj, buf_size=1024, decoder=JSONDecoder()):
buf = ""
ex = None
while True:
block = file_obj.read(buf_size)
if not block:
break
buf += block
pos = 0
while True:
match = NOT_WHITESPACE.search(buf, pos)
if not match:
break
pos = match.start()
try:
obj, pos = decoder.raw_decode(buf, pos)
except JSONDecodeError as e:
ex = e
break
else:
ex = None
yield obj
buf = buf[pos:]
if ex is not None:
raise ex