13.4. lzma — 使用 LZMA 算法进行压缩 — Python 文档

来自菜鸟教程
Python/docs/3.6/library/lzma
跳转至:导航、​搜索

13.4. lzma — 使用 LZMA 算法进行压缩

3.3 版中的新功能。


源代码: :source:`Lib/lzma.py`



该模块提供了使用 LZMA 压缩算法压缩和解压缩数据的类和便利函数。 还包括一个文件接口,支持 .xzxz 实用程序使用的传统 .lzma 文件格式,以及原始压缩流。

该模块提供的接口与bz2模块非常相似。 但是,请注意 LZMAFilenot 线程安全的,不像 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 参数可以是实际的文件名(作为 strbytespath-like 对象),其中如果指定的文件被打开,或者它可以是要读取或写入的现有文件对象。

mode 参数可以是 "r""rb""w""wb""x""xb""a""ab" 用于二进制模式,或 "rt""wt""xt" 或 ] 用于文本模式。 默认值为 "rb"

打开文件进行读取时,formatfilters 参数与 LZMADecompressor 参数具有相同的含义。 在这种情况下,不应使用 checkpreset 参数。

打开文件进行写入时,formatcheckpresetfilters参数与LZMACompressor的含义相同

对于二进制模式,此函数等效于 LZMAFile 构造函数:LZMAFile(filename, mode, ...)。 在这种情况下,不得提供 encodingerrorsnewline 参数。

对于文本模式,会创建一个 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 参数指定要包装的文件对象或要打开的文件的名称(作为 strbytespath-like 对象)。 包装现有文件对象时,当关闭 LZMAFile 时,包装的文件不会被关闭。

mode 参数可以是用于读取的 "r"(默认)、用于覆盖的 "w"、用于独占创建的 "x""a"用于附加。 这些可以分别等效地表示为 "rb""wb""xb""ab"

如果 filename 是文件对象(而不是实际文件名),则 "w" 模式不会截断文件,而是等效于 "a"

当打开一个文件进行读取时,输入文件可能是多个单独的压缩流的串联。 这些被透明地解码为单个逻辑流。

打开文件进行读取时,formatfilters 参数与 LZMADecompressor 参数具有相同的含义。 在这种情况下,不应使用 checkpreset 参数。

打开文件进行写入时,formatcheckpresetfilters参数与LZMACompressor的含义相同

LZMAFile 支持 io.BufferedIOBase 指定的所有成员,除了 detach()truncate()。 支持迭代和 with 语句。

还提供了以下方法:

peek(size=- 1)

返回缓冲数据而不推进文件位置。 除非达到 EOF,否则将返回至少 1 个字节的数据。 返回的确切字节数未指定(忽略 size 参数)。

笔记

虽然调用 peek() 不会改变 LZMAFile 的文件位置,但它可能会改变底层文件对象的位置(例如 如果 LZMAFile 是通过为 filename 传递文件对象来构造的)。

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_ALONEFORMAT_RAW 的默认值(也是唯一可接受的值)。

  • CHECK_CRC32:32 位循环冗余校验。

  • CHECK_CRC64:64 位循环冗余校验。 这是 FORMAT_XZ 的默认设置。

  • CHECK_SHA256:256 位安全哈希算法。

如果不支持指定的检查,则会引发 LZMAError

压缩设置可以指定为预设压缩级别(使用 preset 参数),也可以详细指定为自定义过滤器链(使用 filters 参数)。

preset 参数(如果提供)应该是一个介于 09(含)之间的整数,可选择与常量 PRESET_EXTREME 进行或运算。 如果没有给出 presetfilters,默认行为是使用 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_XZFORMAT_ALONEFORMAT_RAW

memlimit 参数指定解压缩器可以使用的内存量的限制(以字节为单位)。 使用此参数时,如果无法在给定的内存限制内解压缩输入,解压缩将失败并显示 LZMAError

filters 参数指定用于创建正在解压缩的流的过滤器链。 如果 formatFORMAT_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 对象返回。

有关 formatcheckpresetfilters 参数的说明,请参阅上面的 LZMACompressor

lzma.decompress(data, format=FORMAT_AUTO, memlimit=None, filters=None)

解压 data(一个 bytes 对象),将未压缩的数据作为 bytes 对象返回。

如果 data 是多个不同压缩流的串联,则解压缩所有这些流,并返回结果的串联。

有关 formatmemlimitfilters 参数的说明,请参阅上面的 LZMADecompressor


13.4.3. 各种各样的

lzma.is_check_supported(check)

如果此系统支持给定的完整性检查,则返回 true。

始终支持 CHECK_NONECHECK_CRC32CHECK_CRC64CHECK_SHA256 如果您使用的 liblzma 版本是用有限的功能集编译的,则可能不可用。


13.4.4. 指定自定义过滤器链

过滤器链说明符是一系列字典,其中每个字典都包含单个过滤器的 ID 和选项。 每个字典必须包含键 "id",并且可能包含附加键以指定依赖于过滤器的选项。 有效的过滤器 ID 如下:

  • *; 压缩过滤器:
    *;* FILTER_LZMA1(用于 FORMAT_ALONE
    • FILTER_LZMA2(用于 FORMAT_XZFORMAT_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。
  • modeMODE_FASTMODE_NORMAL
  • nice_len:对于一场比赛来说,什么应该被认为是“不错的长度”。 这应该是 273 或更少。
  • mf:使用什么匹配查找器 - MF_HC3MF_HC4MF_BT2MF_BT3MF_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")