13.4. lzma — 使用 LZMA 算法进行压缩 — Python 文档
13.4. lzma — 使用 LZMA 算法进行压缩
3.3 版中的新功能。
该模块提供了使用 LZMA 压缩算法压缩和解压缩数据的类和便利函数。 还包括一个文件接口,支持 .xz
和 xz 实用程序使用的传统 .lzma
文件格式,以及原始压缩流。
该模块提供的接口与bz2模块非常相似。 但是,请注意 LZMAFile 是 not 线程安全的,不像 bz2.BZ2File,所以如果您需要使用单个 LZMAFile 实例从多个线程,有必要用锁来保护它。
- exception lzma.LZMAError
- 当在压缩或解压缩过程中或在初始化压缩器/解压缩器状态时发生错误时,会引发此异常。
13.4.1. 读取和写入压缩文件
- lzma.open(filename, mode="rb", \*, format=None, check=-1, preset=None, filters=None, encoding=None, errors=None, newline=None)
以二进制或文本模式打开 LZMA 压缩文件,返回 文件对象 。
filename 参数可以是实际的文件名(作为 str、bytes 或 path-like 对象),其中如果指定的文件被打开,或者它可以是要读取或写入的现有文件对象。
mode 参数可以是
"r"
、"rb"
、"w"
、"wb"
、"x"
、"xb"
、"a"
或"ab"
用于二进制模式,或"rt"
、"wt"
、"xt"
或 ] 用于文本模式。 默认值为"rb"
。打开文件进行读取时,format 和 filters 参数与 LZMADecompressor 参数具有相同的含义。 在这种情况下,不应使用 check 和 preset 参数。
打开文件进行写入时,format、check、preset和filters参数与LZMACompressor的含义相同。
对于二进制模式,此函数等效于 LZMAFile 构造函数:
LZMAFile(filename, mode, ...)
。 在这种情况下,不得提供 encoding、errors 和 newline 参数。对于文本模式,会创建一个 LZMAFile 对象,并将其包装在具有指定编码、错误处理行为和行尾的 io.TextIOWrapper 实例中。
3.4 版更改: 添加了对
"x"
、"xb"
和"xt"
模式的支持。3.6 版更改: 接受 类路径对象 。
- class lzma.LZMAFile(filename=None, mode="r", \*, format=None, check=-1, preset=None, filters=None)
以二进制模式打开 LZMA 压缩文件。
LZMAFile 可以包装一个已经打开的 文件对象 ,或者直接对命名文件进行操作。 filename 参数指定要包装的文件对象或要打开的文件的名称(作为 str、bytes 或 path-like 对象)。 包装现有文件对象时,当关闭 LZMAFile 时,包装的文件不会被关闭。
mode 参数可以是用于读取的
"r"
(默认)、用于覆盖的"w"
、用于独占创建的"x"
或"a"
用于附加。 这些可以分别等效地表示为"rb"
、"wb"
、"xb"
和"ab"
。如果 filename 是文件对象(而不是实际文件名),则
"w"
模式不会截断文件,而是等效于"a"
。当打开一个文件进行读取时,输入文件可能是多个单独的压缩流的串联。 这些被透明地解码为单个逻辑流。
打开文件进行读取时,format 和 filters 参数与 LZMADecompressor 参数具有相同的含义。 在这种情况下,不应使用 check 和 preset 参数。
打开文件进行写入时,format、check、preset和filters参数与LZMACompressor的含义相同。
LZMAFile 支持 io.BufferedIOBase 指定的所有成员,除了
detach()
和truncate()
。 支持迭代和 with 语句。还提供了以下方法:
- peek(size=- 1)
返回缓冲数据而不推进文件位置。 除非达到 EOF,否则将返回至少 1 个字节的数据。 返回的确切字节数未指定(忽略 size 参数)。
3.4 版更改: 添加了对
"x"
和"xb"
模式的支持。3.5 版更改: read() 方法现在接受
None
的参数。3.6 版更改: 接受 类路径对象 。
13.4.2. 压缩和解压缩内存中的数据
- class lzma.LZMACompressor(format=FORMAT_XZ, check=- 1, preset=None, filters=None)
创建一个压缩器对象,可用于增量压缩数据。
有关压缩单个数据块的更方便的方法,请参阅 compress()。
format 参数指定应该使用什么容器格式。 可能的值为:
FORMAT_XZ
:.xz
容器格式。这是默认格式。
FORMAT_ALONE
:传统的.lzma
容器格式。这种格式比
.xz
更受限制——它不支持完整性检查或多个过滤器。
FORMAT_RAW
:原始数据流,不使用任何容器格式。此格式说明符不支持完整性检查,并要求您始终指定自定义过滤器链(用于压缩和解压缩)。 此外,以这种方式压缩的数据不能使用
FORMAT_AUTO
解压缩(参见 LZMADecompressor)。
check 参数指定要包含在压缩数据中的完整性检查类型。 解压缩时使用此检查,以确保数据未损坏。 可能的值为:
CHECK_NONE
:无完整性检查。 这是FORMAT_ALONE
和FORMAT_RAW
的默认值(也是唯一可接受的值)。CHECK_CRC32
:32 位循环冗余校验。CHECK_CRC64
:64 位循环冗余校验。 这是FORMAT_XZ
的默认设置。CHECK_SHA256
:256 位安全哈希算法。
如果不支持指定的检查,则会引发 LZMAError。
压缩设置可以指定为预设压缩级别(使用 preset 参数),也可以详细指定为自定义过滤器链(使用 filters 参数)。
preset 参数(如果提供)应该是一个介于
0
和9
(含)之间的整数,可选择与常量PRESET_EXTREME
进行或运算。 如果没有给出 preset 和 filters,默认行为是使用PRESET_DEFAULT
(预设级别6
)。 较高的预设产生较小的输出,但会使压缩过程变慢。笔记
除了更多的 CPU 密集型之外,具有更高预设的压缩还需要更多的内存(并且产生需要更多内存来解压缩的输出)。 以预设
9
为例,LZMACompressor 对象的开销可高达 800 MiB。 出于这个原因,通常最好坚持使用默认预设。filters 参数(如果提供)应该是一个过滤器链说明符。 有关详细信息,请参阅 指定自定义过滤器链 。
- compress(data)
压缩 data(一个 bytes 对象),返回一个 bytes 对象,其中包含至少部分输入的压缩数据。 一些 data 可能会在内部缓冲,以用于以后对 compress() 和 flush() 的调用。 返回的数据应该与之前对 compress() 的任何调用的输出连接在一起。
- flush()
完成压缩过程,返回一个 bytes 对象,其中包含存储在压缩器内部缓冲区中的任何数据。
调用此方法后无法使用压缩器。
- class lzma.LZMADecompressor(format=FORMAT_AUTO, memlimit=None, filters=None)
创建一个解压器对象,可以用来增量解压数据。
有关一次解压缩整个压缩流的更方便的方法,请参阅 decompress()。
format 参数指定应该使用的容器格式。 默认为
FORMAT_AUTO
,可以解压.xz
和.lzma
文件。 其他可能的值为FORMAT_XZ
、FORMAT_ALONE
和FORMAT_RAW
。memlimit 参数指定解压缩器可以使用的内存量的限制(以字节为单位)。 使用此参数时,如果无法在给定的内存限制内解压缩输入,解压缩将失败并显示 LZMAError。
filters 参数指定用于创建正在解压缩的流的过滤器链。 如果 format 是
FORMAT_RAW
,则此参数是必需的,但不应用于其他格式。 有关过滤器链的更多信息,请参阅 指定自定义过滤器链 。笔记
与 decompress() 和 LZMAFile 不同,此类不会透明地处理包含多个压缩流的输入。 要使用 LZMADecompressor 解压缩多流输入,您必须为每个流创建一个新的解压缩器。
- decompress(data, max_length=- 1)
解压缩 data(一个 bytes-like object),以字节形式返回未压缩的数据。 某些 data 可能会在内部进行缓冲,以供以后调用 decompress() 时使用。 返回的数据应该与之前对 decompress() 的任何调用的输出连接在一起。
如果 max_length 为非负数,则最多返回 max_length 个字节的解压缩数据。 如果达到此限制并且可以产生更多输出,则 needs_input 属性将设置为
False
。 在这种情况下,下一次调用 decompress() 可能会提供 data 作为b
以获得更多输出。如果所有输入数据都被解压缩并返回(因为这小于 max_length 个字节,或者因为 max_length 是负数),needs_input 属性将是设置为
True
。在到达流末尾后尝试解压缩数据会引发 EOFError。 在流结束后找到的任何数据都将被忽略并保存在 unused_data 属性中。
3.5 版更改: 添加 max_length 参数。
- check
输入流使用的完整性检查的 ID。 这可能是
CHECK_UNKNOWN
,直到足够的输入被解码以确定它使用什么完整性检查。
- eof
True
如果已到达流结束标记。
- unused_data
在压缩流结束后找到的数据。
在到达流的末尾之前,这将是
b""
。
- needs_input
False
如果 decompress() 方法可以在需要新的未压缩输入之前提供更多的解压缩数据。3.5 版中的新功能。
- lzma.compress(data, format=FORMAT_XZ, check=- 1, preset=None, filters=None)
压缩 data(一个 bytes 对象),将压缩数据作为 bytes 对象返回。
有关 format、check、preset 和 filters 参数的说明,请参阅上面的 LZMACompressor。
- lzma.decompress(data, format=FORMAT_AUTO, memlimit=None, filters=None)
解压 data(一个 bytes 对象),将未压缩的数据作为 bytes 对象返回。
如果 data 是多个不同压缩流的串联,则解压缩所有这些流,并返回结果的串联。
有关 format、memlimit 和 filters 参数的说明,请参阅上面的 LZMADecompressor。
13.4.3. 各种各样的
- lzma.is_check_supported(check)
如果此系统支持给定的完整性检查,则返回 true。
始终支持
CHECK_NONE
和CHECK_CRC32
。CHECK_CRC64
和CHECK_SHA256
如果您使用的 liblzma 版本是用有限的功能集编译的,则可能不可用。
13.4.4. 指定自定义过滤器链
过滤器链说明符是一系列字典,其中每个字典都包含单个过滤器的 ID 和选项。 每个字典必须包含键 "id"
,并且可能包含附加键以指定依赖于过滤器的选项。 有效的过滤器 ID 如下:
- *; 压缩过滤器:
- *;*
FILTER_LZMA1
(用于FORMAT_ALONE
)
FILTER_LZMA2
(用于FORMAT_XZ
和FORMAT_RAW
)
- *;*
- *; 三角洲过滤器:
- *;*
FILTER_DELTA
- *;*
- *; 分支呼叫跳转 (BCJ) 过滤器:
- *;*
FILTER_X86
FILTER_IA64
FILTER_ARM
FILTER_ARMTHUMB
FILTER_POWERPC
FILTER_SPARC
- *;*
一个过滤器链最多可以包含 4 个过滤器,并且不能为空。 链中的最后一个过滤器必须是压缩过滤器,任何其他过滤器必须是 delta 或 BCJ 过滤器。
压缩过滤器支持以下选项(指定为代表过滤器的字典中的附加条目):
preset
:压缩预设用作未明确指定的选项的默认值来源。dict_size
:字典大小(以字节为单位)。 这应该介于 4 KiB 和 1.5 GiB(含)之间。lc
:文字上下文位数。lp
:文字位置位数。 总和lc + lp
必须最多为 4。pb
:位置位数; 最多必须为 4。mode
:MODE_FAST
或MODE_NORMAL
。nice_len
:对于一场比赛来说,什么应该被认为是“不错的长度”。 这应该是 273 或更少。mf
:使用什么匹配查找器 -MF_HC3
、MF_HC4
、MF_BT2
、MF_BT3
或MF_BT4
。depth
:匹配查找器使用的最大搜索深度。 0(默认)表示根据其他过滤器选项自动选择。
delta 过滤器存储字节之间的差异,在某些情况下为压缩器产生更多重复的输入。 它支持一个选项,dist
。 这表示要减去的字节之间的距离。 默认为1,即 取相邻字节之间的差异。
BCJ 过滤器旨在应用于机器代码。 它们将代码中的相对分支、调用和跳转转换为使用绝对寻址,目的是增加压缩器可以利用的冗余。 这些过滤器支持一个选项,start_offset
。 这指定了应该映射到输入数据开头的地址。 默认值为 0。
13.4.5. 例子
读入压缩文件:
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
data_in = b"Insert Data Here"
data_out = lzma.compress(data_in)
增量压缩:
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()
# Concatenate all the partial results:
result = b"".join([out1, out2, out3, out4])
将压缩数据写入已打开的文件:
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")
使用自定义过滤器链创建压缩文件:
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")