Skip to content

jsonlines

jsonlines用于解析 jsonlines 格式的数据。尽管 jsonlines 非常简单但是依然会遇到一些问题,而 jsonlines 是一个非常短小精悍的库,提供了:

  • 通明处理 str/bytes 的输入输出
  • 支持不同的 JSON 库来编码或解析(默认 json)
  • 透明处理 utf-8 BOM(如果存在)
  • 更加友好的错误信息
  • Pythonic 的编程接口

安装

Bash
pip install jsonlines

conda install jsonlines

入口函数: open()

jsonlines 提供了一个入口函数 open 来根据 mode 返回 Reader 和 Writer,以及其他属性来定义 Reader/Writer 的行为:

Python
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)。

Python
with jsonlines.open('out.jsonl', mode='w') as writer:
    writer.write(...)

Reader 和 Writer 对象

入口函数 open 最终返回的是 Reader 和 Writer 对象,他们最核心的区别就是:

  • open 只能接受文件路径对象
  • Reader 和 Writer 接受类文件对象,这意味着它支持压缩流等操作

Tips

要注意 file-like objectpath-like object

Reader

mode = 'r' 即默认时,open 会返回 Reader,并且他还可以根据传入进来的 loads 替换默认的解码器(默认是标准库提供的 json)

Reader 是可迭代的,并且可以使用上下文管理器。因此最基本的使用方法是:

Python
with jsonlines.open('in.jsonl') as reader:
    for line in reader:
        print(line)

当然如果想要更加细节的控制迭代器的行为也可以使用 Reader.iter():

Python
def iter(
    allow_none: bool = False,  # 静默允许 None
    skip_empty: bool = False,  # 静默跳过行
    skip_invalid: bool = False # 静默跳过无效行(通常是编码错误)
) -> Iterator

直接对 Reader 的默认行为遇到 None、Empty 或 invalid 会抛出异常,如果不希望可以使用 iter 来定制迭代器的行为:

Python
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 可以使用上下文管理器。因此最基本的使用方法是:

Python
with jsonlines.open('out.jsonl', mode='w') as writer:
    writer.write(any)
    # 如果需要批量写入
    writer.write_all(iterable)

对压缩文件的支持

Reader 和 Writer 能够单独使用,此时它接受一个类文件对象,最常见的使用场景就是接受通过 gzip 等打开的 fp 来作为写入/读取源,能够直接对压缩文件进行操作:

Python
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 接受的是类文件路径对象