jsonlines
jsonlines用于解析 jsonlines 格式的数据。尽管 jsonlines 非常简单但是依然会遇到一些问题,而 jsonlines 是一个非常短小精悍的库,提供了:
- 通明处理 str/bytes 的输入输出
- 支持不同的 JSON 库来编码或解析(默认 json)
- 透明处理 utf-8 BOM(如果存在)
- 更加友好的错误信息
- Pythonic 的编程接口
安装
入口函数: open()
jsonlines 提供了一个入口函数 open 来根据 mode 返回 Reader 和 Writer,以及其他属性来定义 Reader/Writer 的行为:
import jsonlines
jsonlines.open(
file: str|bytes|Path, # 路径字符串或路径对象
mode: Literal['r', 'w', 'a', 'x'] = 'r', # r 返回 Reader w|a|x 返回 Writer
dumps: Callable[[Any], str|bytes]|None = None, # 编码器(Writer)
loads: Callable[[str|bytes], Any]|None = None, # 解码器(Reader)
compact: bool|None = None, # 紧凑格式输出(Writer)
sort_keys: bool|None = None, # 根据对象键进行排序(Writer)
flush: bool|None = None # 写入的每一行都先 flush 到磁盘(Writer)
) -> Reader | Writer
pass
它是一个方便的函数,用于打开文件并根据 mode 将其包装为对 jsonlines 格式的读取器(Reader)或写入器(Writer)。
Reader 和 Writer 对象
入口函数 open 最终返回的是 Reader 和 Writer 对象,他们最核心的区别就是:
- open 只能接受文件路径对象
- Reader 和 Writer 接受类文件对象,这意味着它支持压缩流等操作
Tips
要注意 file-like object 和 path-like object
Reader
当 mode = 'r'
即默认时,open 会返回 Reader,并且他还可以根据传入进来的 loads 替换默认的解码器(默认是标准库提供的 json)。
Reader 是可迭代的,并且可以使用上下文管理器。因此最基本的使用方法是:
当然如果想要更加细节的控制迭代器的行为也可以使用 Reader.iter()
:
def iter(
allow_none: bool = False, # 静默允许 None
skip_empty: bool = False, # 静默跳过行
skip_invalid: bool = False # 静默跳过无效行(通常是编码错误)
) -> Iterator
直接对 Reader 的默认行为遇到 None、Empty 或 invalid 会抛出异常,如果不希望可以使用 iter 来定制迭代器的行为:
with jsonlines.open('in.jsonl') as reader:
for line in reader.iter(skip_invalid=True):
print(line)
Writer
当 mode = 'w'/'x'/'a'
时,open 会返回 Writer,并且他还可以根据传入进来的 dumps 替换默认的编码器(默认是标准库提供的 json)。
Writer 可以使用上下文管理器。因此最基本的使用方法是:
with jsonlines.open('out.jsonl', mode='w') as writer:
writer.write(any)
# 如果需要批量写入
writer.write_all(iterable)
对压缩文件的支持
Reader 和 Writer 能够单独使用,此时它接受一个类文件对象,最常见的使用场景就是接受通过 gzip 等打开的 fp 来作为写入/读取源,能够直接对压缩文件进行操作:
import gzip
import jsonlines
# 写入数据并直接压缩
with gzip.open("out.jsonl.gz", "w") as fp:
with jsonlines.Writer(fp) as writer:
d = {"hello": "world"}
writer.write(d)
# 直接读取压缩数据
with gzip.open("out.jsonl.gz") as fp:
with jsonlines.Reader(fp) as reader:
for line in reader:
print(line)
Tips
注意要直接使用 Writer/Reader 来包装,而不是使用 open 这个便捷方法,open 接受的是类文件路径对象。