首页
/ CPython lzma 模块完全指南:liblzma 压缩接口、.xz/.lzma 文件读写与自定义过滤器链

CPython lzma 模块完全指南:liblzma 压缩接口、.xz/.lzma 文件读写与自定义过滤器链

2026-09-07 09:21:45作者:温艾琴Wonderful

本文以 CPython 官方库文档 Doc/library/lzma.rst 为核心骨架,系统讲解标准库 lzma 模块在 Python 中的完整用法:包括文件级 API lzma.open() / LZMAFile 读写 .xz.lzma 与裸压缩流,内存级增量压缩 LZMACompressor / LZMADecompressor,以及面向高级场景的过滤器链(Filter Chain)配置与全部模块常量。读完本文,你将能够用 Python 直接读写 xz 工具产出的压缩包、处理拼接式多流文件、按需设置压缩预设与内存上限,并深入理解 lzma 模块背后“纯 Python 文件接口 + C 扩展 _lzma 增量编解码器”的分层实现(对应源码 Lib/lzma.pyModules/_lzmamodule.c)。

一、模块概览:lzma 是什么

lzma 是 Python 标准库中基于 liblzma 压缩库(即 xz 工具背后所用的 XZ Utils 库)的封装模块。自 Python 3.3 引入以来(文档注明 versionadded: 3.3),它为开发者提供了三类能力:

  • 类与便捷函数:用于压缩与解压内存中的字节数据;
  • 文件接口:支持 .xz 容器格式、遗留的 .lzma 容器格式(由命令行工具 xz 使用),以及不带任何容器头的裸压缩流(raw stream)
  • 完整的常量体系:包括容器格式、完整性校验类型、压缩预设与过滤器 ID 等。

从接口风格上讲,文档明确指出 “该模块提供的接口与 bz2 模块非常相似”。从当前仓库(main 开发分支)的源码结构看,这一相似性得到了更深的体现:LZMAFilebz2.BZ2Filegzip 的实现都迁移到了共享的 compression._common._streams 基础设施上,复用了 Lib/compression/_common/_streams.py 中的 BaseStreamDecompressReader 等流抽象类,并把模块本体挂入新的 compression 命名空间包(见 Lib/compression/lzma.py,它负责从顶层 lzma 模块重导出全部公开符号)。

线程安全提示

文档特别提醒:LZMAFilebz2.BZ2File 不是线程安全的。如果要在多个线程中共用同一个 LZMAFile 实例,必须用锁(如 threading.Lock)对其进行保护,或为每个线程各自创建独立实例。

关于可选模块与发行版差异

lzma 属于可选模块(optional module)。若你的 Python 安装中缺少它,文档建议查阅发行方(即提供该 Python 构建的一方)的文档;对发行方而言则可参考仓库内 Doc/includes/optional-module.rst 指向的 optional-module-requirements 说明。底层对应关系可见构建配置文件 Modules/Setup.stdlib.in_lzma _lzmamodule.c 一行显示该扩展需链接系统 liblzma(对应注释中 -llzma),因此系统缺少 liblzma 开发库或链接的是受限功能版 liblzma 时,部分能力(如特定校验算法)会不可用。

分层实现:Python 文件层 + C 增量编解码器

当前仓库的实现可概括为两层(这是从 Lib/lzma.py 源码可以直接读到的结构):

层次 实现位置 职责
高层文件接口 Lib/lzma.pyLZMAFileopencompressdecompress 均为纯 Python) 文件对象封装、文本模式、seek 模拟、多流拼接触发器
底层增量编解码器 Modules/_lzmamodule.c_lzma C 扩展 LZMACompressorLZMADecompressorLZMAError、全部常量、is_check_supported()

Lib/lzma.py 第 29~30 行通过 from _lzma import * 直接导入 C 扩展的压缩器/解压器类型与常量,因此 Python 层无需关心 liblzma 的底层调用细节。

二、异常类型:LZMAError

模块定义了一个异常类型:

import lzma

try:
    lzma.compress(b"data", format=lzma.FORMAT_ALONE, check=lzma.CHECK_CRC32)  # ALONE 不支持完整性校验
except lzma.LZMAError as e:
    print("压缩失败:", e)

lzma.LZMAError 在压缩、解压出错,或初始化压缩器/解压器状态时抛出。在 C 源码中它通过 PyErr_NewExceptionWithDoc("_lzma.LZMAError", ...) 创建(见 Modules/_lzmamodule.clzma_exec 函数),Python 层再将其原样重导出为 lzma.LZMAError

典型触发场景包括:

  • 指定了不支持的完整性校验类型(如对 FORMAT_ALONE 使用 CHECK_CRC32);
  • 解压时内存超出 memlimit 限制;
  • 数据损坏、截断(解压未达流结束标记);
  • 使用 FORMAT_RAW 却未提供 filters 过滤器链。

三、读取与写入压缩文件

3.1 函数签名与总体行为

lzma.open(filename, mode="rb", *, format=None, check=-1, preset=None,
          filters=None, encoding=None, errors=None, newline=None)

lzma.open()二进制模式或文本模式打开一个 LZMA 压缩文件,返回一个 file object。它的核心行为在 Lib/lzma.pyopen() 函数中有清晰实现:先剔除模式字符串中的 "t" 以构建 LZMAFile,二进制模式直接返回该对象;文本模式则再包一层 io.TextIOWrapper,并用 io.text_encoding(encoding) 处理默认编码(源码见 Lib/lzma.py)。

filename 参数可以是:

  • 一个真正的文件名:strbytes 或 path-like 对象(实现了 os.PathLike),此时打开该命名的文件;
  • 一个已打开的 file object:直接在该对象上进行读写。

mode 参数可取如下值:

类别 取值 说明
二进制模式 "r" / "rb" 读(默认)
二进制模式 "w" / "wb" 覆盖写
二进制模式 "x" / "xb" 独占创建(文件已存在则报错)
二进制模式 "a" / "ab" 追加写
文本模式 "rt" 文本读
文本模式 "wt" 文本覆盖写
文本模式 "xt" 文本独占创建
文本模式 "at" 文本追加

默认 mode 为 "rb"。模式的历史演进见文档版本注记:"x""xb""xt" 模式自 Python 3.4 起支持;3.6 起 filename 接受 path-like 对象。

参数语义随打开方式而变(这一点与 LZMAFileLZMACompressorLZMADecompressor 保持一致):

  • 读模式下,formatfilters 的含义等同于 LZMADecompressor;此时不应使用 checkpreset(若传了会在底层报 ValueError);
  • 写模式下,formatcheckpresetfilters 的含义等同于 LZMACompressor

二进制模式下 lzma.open(filename, mode, ...)LZMAFile(filename, mode, ...) 构造器完全等价;此时不得提供 encodingerrorsnewline。文本模式则基于 LZMAFile 外层包裹 io.TextIOWrapper,按指定的编码、错误处理策略与换行符规则工作。

3.2 LZMAFile 类:面向二进制文件对象的完整封装

lzma.LZMAFile(filename=None, mode="r", *, format=None, check=-1,
              preset=None, filters=None)

LZMAFile 以二进制模式打开 LZMA 压缩文件。它的关键设计点如下:

① 包装 vs 自开文件。 filename 既可以是已打开的文件对象(此时 LZMAFile 关闭时不会关闭被包装的底层文件),也可以是文件名。当前实现中,当 filenamestr/bytes/os.PathLike 时会以 builtins.open 自行打开并置 _closefp=True,否则视为已打开的文件对象(见 Lib/lzma.py)。

② mode 语义。 mode 可以是 "r"(默认,读)、"w"(覆盖写)、"x"(独占创建)、"a"(追加),也可以等价写成 "rb""wb""xb""ab"。特别地:若 filename 是文件对象(而非文件名),"w" 不会截断该文件,而是等价于 "a"(因为追加写发生在当前文件位置)。"x""xb" 模式自 3.4 起支持。

③ 读取多流拼接文件。 读模式下输入文件可以是多个独立压缩流的拼接(例如用 xz filecat a.xz b.xz > c.xz 式操作拼出的文件),LZMAFile 会把它们当作一条逻辑流透明解码。Python 层实现通过 DecompressReader + io.BufferedReader 完成(见 Lib/lzma.py)。写模式的格式默认值为 FORMAT_XZ,读模式默认值为 FORMAT_AUTO(见 Lib/lzma.py)。

④ 支持的接口范围。 LZMAFile 支持 io.BufferedIOBase 的全部成员,除了 detach()truncate();支持迭代与 with 语句。它额外提供:

  • peek(size=-1):返回缓冲数据但不推进文件位置。除非已达 EOF,否则至少返回 1 字节;精确返回多少字节未定义(size 参数被忽略)。注意:调用 peek 不改变 LZMAFile 自身的位置,但可能改变底层文件对象的位置(例如当 filename 传入的是一个文件对象时)。
  • mode 属性(3.13 新增):读模式为 'rb',写模式为 'wb'。当前实现中以 _MODE_READ/_MODE_WRITE 内部标记推导(见 Lib/lzma.py)。
  • name 属性(3.13 新增):lzma 文件名,等价于底层 file object 的 FileIO.name

⑤ 读写语义与 seek。 write(data) 返回未压缩数据的字节数(即 len(data)),数据因缓冲未必立即落盘,直到 close() 时才会写入压缩器 flush() 的余量(见 Lib/lzma.py)。seek() 是被模拟的(基于 BufferedReader 解压重放),因此某些参数组合下可能极慢;文档同时注明 3.5 起 read() 接受 None 参数。

3.3 文件读写实战示例

文档中的示例均可直接运行,以下是按场景组织的完整示范:

读取压缩文件:

import lzma

with lzma.open("file.xz") as f:
    file_content = f.read()

创建压缩文件:

import lzma

data = b"Insert Data Here"
with lzma.open("file.xz", "w") as f:
    f.write(data)

向一个已打开的文件中写入压缩数据(压缩与非压缩内容混写):

import lzma

with open("file.xz", "wb") as f:
    f.write(b"This data will not be compressed\n")
    with lzma.open(f, "w") as lzf:
        lzf.write(b"This *will* be compressed\n")
    f.write(b"Not compressed\n")

说明:上面第三段示例向已打开的 file object 写入。由于 LZMAFile 包装文件对象时不会接管其关闭权,with 退出只冲刷压缩器,不会关掉外层的 f;且如文档所述,此场景下 "w" 不截断文件,实际等价于追加。

使用自定义过滤器链创建压缩文件:

import lzma

my_filters = [
    {"id": lzma.FILTER_DELTA, "dist": 5},
    {"id": lzma.FILTER_LZMA2, "preset": 7 | lzma.PRESET_EXTREME},
]
with lzma.open("file.xz", "w", filters=my_filters) as f:
    f.write(b"blah blah blah")

四、在内存中压缩与解压数据

4.1 LZMACompressor:增量压缩器

lzma.LZMACompressor(format=FORMAT_XZ, check=-1, preset=None, filters=None)

LZMACompressor 用于增量压缩。若只需一次性压缩一小段数据,应优先使用便捷函数 lzma.compress()

各参数语义:

  • format:指定容器格式,可取 FORMAT_XZ(默认)、FORMAT_ALONEFORMAT_RAW。在 C 扩展的参数解析中,format 的默认值即为 FORMAT_XZ(见 Modules/_lzmamodule.c)。
  • check:写入压缩数据中的完整性校验类型,解压时用于确认数据未被损坏。可取 CHECK_NONECHECK_CRC32CHECK_CRC64FORMAT_XZ 的默认)、CHECK_SHA256。指定了不支持的校验类型会抛 LZMAError
  • presetfilters 二选一:压缩设置要么用预设级别 preset 简写,要么用 filters 自定义过滤器链细粒度指定,两者不能同时提供(_lzma 会对“同时给出 preset 与 filters”抛错,测试用例见 Lib/test/test_lzma.pyLZMACompressor(preset=7, filters=[...]) 的相关断言)。

preset 若提供,应是一个 0 到 9(含)之间的整数,可再按位或上 PRESET_EXTREME。若既不提供 preset 也不提供 filters,默认采用 PRESET_DEFAULT(即预设级别 6)。级别越高输出越小,但压缩越慢。

内存代价警告(文档重点提示): 高预设不仅更耗 CPU,还需要大量内存(解压同样需要更多内存)。例如预设 9 时,一个 LZMACompressor 对象的开销可高达 800 MiB。因此一般建议使用默认预设。这与 xz 工具的行为一致——追求极限压缩比必须付出内存与时间成本。

实例方法:

  • compress(data):压缩一段 bytes 数据,返回包含至少部分输入压缩结果的 bytes。部分 data 可能被内部缓冲以用于后续 compress()/flush() 调用。返回数据应与之前所有 compress() 的输出拼接。
  • flush():结束压缩,返回压缩器内部缓冲中的剩余数据。调用后压缩器不可再使用。

增量压缩标准范式(文档原例):

import lzma

lzc = lzma.LZMACompressor()
out1 = lzc.compress(b"Some data\n")
out2 = lzc.compress(b"Another piece of data\n")
out3 = lzc.compress(b"Even more data\n")
out4 = lzc.flush()
# 将所有分片结果拼接起来:
result = b"".join([out1, out2, out3, out4])

4.2 LZMADecompressor:增量解压器

lzma.LZMADecompressor(format=FORMAT_AUTO, memlimit=None, filters=None)

LZMADecompressor 用于增量解压;若想一次解压完整个压缩流,用便捷函数 lzma.decompress() 更方便。

参数语义:

  • format:容器格式。默认 FORMAT_AUTO,可同时解压 .xz.lzma 文件;也可显式指定 FORMAT_XZFORMAT_ALONEFORMAT_RAW
  • memlimit:解压器可用内存上限(字节)。设置后,若给定内存限制内无法完成解压,将抛 LZMAError。这是防御“解压炸弹”的实用手段。
  • filters:创建待解压流所用的过滤器链。当 formatFORMAT_RAW必须提供,其他格式下不应使用。

多流限制(文档重点提示):decompress()LZMAFile 不同,LZMADecompressor 不会透明处理包含多个压缩流的输入。要解压多流输入,必须为每个流各创建一个新解压器

实例方法:

  • decompress(data, max_length=-1):解压 data(bytes-like 对象),返回解压后的 bytes。部分数据可能被内部缓冲用于后续调用,返回结果应与之前所有调用的输出拼接。
    • max_length 非负,最多返回 max_length 字节。若达到上限且仍可产出更多输出,则 needs_input 会被置为 False,此时下一次 decompress() 可传 b'' 以继续取得剩余输出;
    • 若输入全部解压并返回(无论是因为小于 max_length,还是 max_length 为负),needs_input 置为 True
    • 流结束标记之后继续解压会抛 EOFError;流结束标记之后出现的多余数据会被忽略并保存到 unused_data 属性中。
    • max_length 参数自 3.5 加入。

实例属性:

属性 含义
check 输入流所用完整性校验的 ID。在读到足够解码出校验类型的数据前,可能是 CHECK_UNKNOWN
eof 是否已到达流结束标记
unused_data 压缩流结束之后发现的数据;流结束前恒为 b""
needs_input 若为 False,表示 decompress() 在需要新输入前还能产出更多解压数据(3.5 新增)

4.3 单次(一次性)便捷函数

lzma.compress(data, format=FORMAT_XZ, check=-1, preset=None, filters=None)
lzma.decompress(data, format=FORMAT_AUTO, memlimit=None, filters=None)
  • compress(data):压缩 bytes 数据,返回压缩后的 bytes。参数含义同 LZMACompressor。其 Python 实现为 comp.compress(data) + comp.flush()(见 Lib/lzma.py)。
  • decompress(data):解压 bytes,返回解压后的 bytesdata 是多个不同压缩流的拼接,则全部解压并返回拼接结果。 其实现是一个循环:反复用 LZMADecompressor 解压当前数据、检查 eof、取 unused_data 作为下一轮输入,直至没有余量(见 Lib/lzma.py)。参数含义同 LZMADecompressor

内存级压缩的最简用法(文档原例):

import lzma

data_in = b"Insert Data Here"
data_out = lzma.compress(data_in)

五、指定自定义过滤器链(Filter Chain)

当内置预设不足以表达需求时,可把 filters 参数传给压缩器/解压器/文件接口。过滤器链说明符(filter chain specifier)是一个字典组成的序列,每个字典描述一个过滤器,必须含 "id" 键,并可含若干过滤器相关的附加选项键。

一个链条的硬性规则(文档明确):

  • 最多 4 个过滤器,且不能为空
  • 最后一个过滤器必须是压缩过滤器
  • 其余过滤器必须是 delta 或 BCJ 过滤器

5.1 合法过滤器 ID 一览

类别 ID 常量 可用容器格式 备注
压缩过滤器 FILTER_LZMA1 FORMAT_ALONE
压缩过滤器 FILTER_LZMA2 FORMAT_XZFORMAT_RAW
Delta 过滤器 FILTER_DELTA 与任一压缩过滤器配合
BCJ 过滤器 FILTER_X86 同上 适用于 x86 机器码
BCJ 过滤器 FILTER_IA64 同上 Itanium
BCJ 过滤器 FILTER_ARM 同上 ARM
BCJ 过滤器 FILTER_ARMTHUMB 同上 ARM Thumb
BCJ 过滤器 FILTER_POWERPC 同上 PowerPC
BCJ 过滤器 FILTER_SPARC 同上 SPARC
BCJ 过滤器 FILTER_ARM64 同上 要求 lzma 版本 ≥ 5.4.0(文档标记为 next 版本新增)
BCJ 过滤器 FILTER_RISCV 同上 要求 lzma 版本 ≥ 5.6.0(文档标记为 next 版本新增)

FILTER_ARM64FILTER_RISCV 外,其余 BCJ 过滤器在所有 lzma 运行时版本上均可用。

5.2 压缩过滤器选项(LZMA2 / LZMA1)

作为字典的附加键传入。各选项含义与取值范围(文档原述):

含义 取值范围 / 默认
preset 作为未显式指定选项的默认值来源的压缩预设 0~9(可 OR PRESET_EXTREME
dict_size 字典大小(字节) 4 KiB ~ 1.5 GiB(含)
lc 字面量上下文位数(literal context bits) lp 之和 ≤ 4
lp 字面量位置位数(literal position bits) lc + lp ≤ 4
pb 位置位数(position bits) 至多 4
mode 压缩模式 MODE_FASTMODE_NORMAL
nice_len “好的匹配长度”阈值 ≤ 273
mf 匹配查找器 MF_HC3MF_HC4MF_BT2MF_BT3MF_BT4
depth 匹配查找器最大搜索深度 0(默认)表示依据其它选项自动选择

这些选项对应 liblzma lzma_options_lzma 结构体的字段——这正是 XZ Utils 的 LZMA SDK 命名体系:dict_size 决定滑窗大小与解压内存,lc/lp/pb 控制上下文建模的比特分配,mf 决定匹配查找算法(HC 系为哈希链,BT 系为二叉树),而 modenice_len 共同影响压缩速度与比率。

5.3 Delta 过滤器选项

Delta 过滤器存储字节之间的差值,在特定场景(如小整数序列、部分结构化数据)下为压缩器制造更多可压缩的重复输入。它只有一个选项:

  • dist:被减字节之间的距离,默认 1(即相邻字节求差)。示例开篇演示了 {"id": lzma.FILTER_DELTA, "dist": 5} 的用法。

5.4 BCJ(分支-调用-跳转)过滤器选项

BCJ 过滤器面向机器码设计:把代码中的相对分支、调用与跳转转换为绝对寻址,从而增加压缩器可挖掘的冗余。它们只支持一个选项:

  • start_offset:应映射到输入数据起始处的地址,默认 0。当压缩对象会加载到非零基址时,设置该值可进一步提升压缩率。

5.5 组合示例:内存压缩

import lzma

filters = [
    {"id": lzma.FILTER_LZMA2, "preset": 9 | lzma.PRESET_EXTREME,
     "dict_size": 64 * 1024, "lc": 3, "lp": 0, "pb": 2},
]
raw = lzma.compress(b"payload" * 1000, format=lzma.FORMAT_RAW, filters=filters)

六、模块常量参考

以下是用于上述类与函数的 formatcheckpresetfilters 参数的模块级常量。需要指出的是,它们在 C 扩展初始化阶段通过 PyModule_AddIntMacro / module_add_int_constant 从 liblzma 的 LZMA_* 宏直接注册(见 Modules/_lzmamodule.clzma_exec,其中注释说明部分常量超过 32 位,故用 PyLong_FromLongLong 处理,这解释了 CHECK_ID_MAX 等大数值常量在 32 位 long 平台上的正确注册方式)。

6.1 容器格式常量

常量 说明
FORMAT_XZ .xz 容器格式
FORMAT_ALONE 遗留的 .lzma 容器格式。功能受限:不支持完整性校验,也不支持多过滤器
FORMAT_RAW 不使用任何容器格式的裸数据流。不支持完整性校验,且压缩与解压都必须显式提供自定义过滤器链;以该格式压缩的数据无法用 FORMAT_AUTO 解压
FORMAT_AUTO 仅用于解压。自动探测容器格式,从而同时支持 .xz.lzma

6.2 完整性校验常量

常量 说明
CHECK_NONE 无完整性校验。是 FORMAT_ALONEFORMAT_RAW 的默认(也是唯一可接受)取值
CHECK_CRC32 32 位循环冗余校验
CHECK_CRC64 64 位循环冗余校验。FORMAT_XZ 的默认值
CHECK_SHA256 256 位安全散列算法
CHECK_UNKNOWN 流的校验类型尚无法确定;LZMADecompressor.check 在解码出足够输入前可能保持此值
CHECK_ID_MAX 受支持的最大完整性校验 ID

6.3 压缩预设常量

常量 说明
PRESET_DEFAULT 默认压缩预设,等价于预设级别 6
PRESET_EXTREME 可被按位 OR 到预设级别(09)上的标志,用于选择更慢但更彻底的变体

6.4 过滤器 ID 与选项常量

  • 压缩过滤器FILTER_LZMA1(配 FORMAT_ALONE)、FILTER_LZMA2(配 FORMAT_XZ/FORMAT_RAW)。
  • 模式MODE_FASTMODE_NORMAL(作为过滤器说明符的 mode 选项值)。
  • 匹配查找器MF_HC3MF_HC4MF_BT2MF_BT3MF_BT4(作为 mf 选项值)。

七、运行时能力探测:is_check_supported()

lzma.is_check_supported(check) -> bool

返回给定完整性校验在当前系统上是否受支持。CHECK_NONECHECK_CRC32 永远受支持CHECK_CRC64CHECK_SHA256 在你使用的 liblzma 以受限功能集编译时可能不可用。其实现位于 C 扩展的 _lzma.is_check_supported(见 Modules/_lzmamodule.c),直接查询 liblzma 的运行时能力,因此同一安装在不同 liblzma 版本上可能给出不同结果。典型用法是在创建压缩器前先探测目标算法,以便优雅降级:

import lzma

check = lzma.CHECK_SHA256
if lzma.is_check_supported(check):
    data = lzma.compress(b"hello", check=check)
else:
    data = lzma.compress(b"hello", check=lzma.CHECK_CRC64)

八、进阶场景与完整实战

8.1 防御性解压:设置内存上限

import lzma

data = lzma.compress(b"x" * 10_000_000)   # 10 MB 输入
try:
    out = lzma.decompress(data, memlimit=64 * 1024 * 1024)  # 64 MiB 上限
except lzma.LZMAError:
    print("解压所需内存超出限制")

文档说明:一旦传入 memlimit,若无法在限制内完成解压将抛 LZMAError。这对处理不可信输入非常重要——因为如 4.1 节所述,高预设压缩产物在解压时同样需要大内存。

8.2 逐流解压多流输入(LZMADecompressor 版本)

import lzma

def decompress_streams(data):
    """每遇到一个流的结束,就新建解压器处理下一段(unused_data 中的余量)。"""
    result = []
    while data:
        d = lzma.LZMADecompressor()
        result.append(d.decompress(data))
        if not d.eof:
            raise ValueError("数据在流结束标记前截断")
        data = d.unused_data
    return b"".join(result)

文档明确:LZMADecompressor 不像 decompress()/LZMAFile 那样透明合并多流,因此需要手动按 eofunused_data 切换解压器——上面的模式即官方推荐的逐流处理法。

8.3 流式复制(管道式增量处理)

import lzma

def compress_stream(src, dst, chunk=64 * 1024):
    """将已打开的二进制 src 增量压缩后写入 dst。"""
    comp = lzma.LZMACompressor()
    while True:
        block = src.read(chunk)
        if not block:
            break
        dst.write(comp.compress(block))
    dst.write(comp.flush())

with open("plain.bin", "rb") as src, \
     lzma.open("plain.bin.xz", "wb") as dst:
    compress_stream(src, dst)

九、测试与验证线索

CPython 官方对 lzma 的测试集中在 Lib/test/test_lzma.py,是验证本文所述行为最直接的证据源。可重点参考:

  • CompressorDecompressorTestCase:验证增量压缩/解压的正确性,包括非法 preset 类型、preset 与 filters 不能同时给定等约束(对应文档 4.1 节的二选一规则);
  • FileTestCase:验证 LZMAFile 的读写与多流读取,其中 test_init_bad_preset 覆盖了越界 preset(如 10-12**1000、非整数)与读模式禁止 preset 的约束,test_init_with_preset_and_filters 再次确认二者互斥;
  • CompressDecompressFunctionTestCaseOpenTestCase:覆盖便捷函数与 open() 的各类模式/参数组合;
  • MiscellaneousTestCase:覆盖 is_check_supported 等杂项 API;
  • 文件底部还定义了原始过滤器链样本(如 FILTERS_RAW_1 = [{"id": lzma.FILTER_LZMA2, "preset": 3}]),用于 FORMAT_RAW 场景。

十、小结与选型建议

在项目实践中,可以按需在四类入口间选择:

需求 推荐 API
读写 .xz/.lzma 磁盘文件 lzma.open()(文本/二进制),或 LZMAFile(纯二进制、可包装文件对象)
一次性压缩/解压内存数据 lzma.compress() / lzma.decompress()(后者自动处理多流拼接)
大数据流式增量处理 LZMACompressor / LZMADecompressor(注意多流需逐个处理)
精细控制压缩参数 filters 过滤器链(LZMA2 + Delta + BCJ,最多 4 级)

记住几条关键纪律:高 preset(尤其 9)内存开销巨大;解压不可信数据务必设 memlimitLZMAFile/bz2.BZ2File 非线程安全;FORMAT_RAW 压缩的流无法被 FORMAT_AUTO 解压。掌握这些要点后,你在 Python 中处理 XZ 生态数据时便能既高效又安全。

延伸阅读:模块实现 Lib/lzma.py 与 C 扩展 Modules/_lzmamodule.c;共享流基础设施 Lib/compression/_common/_streams.py;构建接入点 Modules/Setup.stdlib.in;接口风格对照 Lib/compression/bz2.py;测试证据 Lib/test/test_lzma.py

登录后查看全文
热门项目推荐
相关项目推荐