compression.zstd --- 与 Zstandard 格式兼容的压缩

Added in version 3.14.

源代码: Lib/compression/zstd/__init__.py


本模块提供了有关使用 Zstandard (或称 zstd) 压缩算法压缩和解压缩数据的类和函数。 zstd 指南 将 Zstandard 描述为“一种快速的无损压缩算法,针对在 zlib 层级和更高压缩率的实时压缩应用场景。” 本模块还包括了一个支持读写由 zstd 工具创建的 .zst 文件以及原始 zstd 压缩流内容的文件接口。

compression.zstd 模块包含:

异常

exception compression.zstd.ZstdError

当在压缩或解压缩期间或是在初始化(解)压缩器状态期间发生错误时此异常会被引发。

读写压缩文件

compression.zstd.open(file, /, mode='rb', *, level=None, options=None, zstd_dict=None, encoding=None, errors=None, newline=None)

以二进制或文本模式打开一个 Zstandard 压缩文件,返回一个 file object

file 参数可以是一个文件名(以 str, bytes路径型 对象的形式给出),在此情况下会打开指定名称的文件,或者可以是一个用于读写的现有文件对象。

mode 参数可以是表示读取的 'rb' (默认值),表示覆写的 'wb',表示追加的 'ab',或者表示独占创建的 'xb'。 这些模式还可分别以 'r', 'w', 'a''x' 的等价形式给出。 你还可以分别使用 'rt', 'wt', 'at''xt' 以文本模式打开。

在读取时,options 参数可以是一个提供高级解压缩形参的字典;请参阅 DecompressionParameter 获取有关受支持形参的详情。 zstd_dict 参数是一个将在解压缩期间使用的 ZstdDict 实例。 在读取时,如果 level 参数不为 None,则会引发 TypeError

在写入时,options 参数可以是一个提供高级压缩形参的字典;请参阅 CompressionParameter 获取有关受支持形参的详情。 level 参数是一个将在写入压缩数据时使用的压缩级别。 leveloptions 只有一个可以为非 None 值。 zstd_dict 参数是一个将在压缩期间使用的 ZstdDict 实例。

在二进制模式下,此函数等同于 ZstdFile 构造器:ZstdFile(file, mode, ...)。在这种情况下,不得提供 encodingerrorsnewline 参数。

在文本模式下,创建一个 ZstdFile 对象,并将其包装在一个 io.TextIOWrapper 实例中,该实例具有指定的编码、错误处理行为和行结束符。

class compression.zstd.ZstdFile(file, /, mode='rb', *, level=None, options=None, zstd_dict=None)

以二进制模式打开一个 Zstandard 压缩文件。

一个 ZstdFile 可以包装一个已经打开的 file object,或者直接操作一个命名文件。file 参数指定要包装的文件对象,或者要打开的文件名(作为 strbytes路径类 对象)。如果包装现有的文件对象,当 ZstdFile 关闭时,包装的文件不会被关闭。

mode 参数可以是 'rb' 用于读取(默认),'wb' 用于覆盖,'xb' 用于独占创建,或者 'ab' 用于追加。 上述模式也可等价地简写为对应的单字符形式: 'r''w''x''a'

如果 file 是文件对象(而不是实际的文件名),'w' 模式不会截断文件,而是等同于 'a'

在读取时,options 参数可以是一个提供高级解压缩形参的字典;请参阅 DecompressionParameter 获取有关受支持形参的详情。 zstd_dict 参数是一个将在解压缩期间使用的 ZstdDict 实例。 在读取时,如果 level 参数不为 None,则会引发 TypeError

在写入时,options 参数可以是一个提供高级解压缩参数的字典;有关支持参数的详细信息,请参阅 CompressionParameterlevel 参数是写入压缩数据时要使用的压缩级别。只能传递 leveloptions 中的一个。zstd_dict 参数是一个在压缩过程中使用的 ZstdDict 实例。

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

还提供了下列方法和属性:

peek(size=-1)

返回缓冲的数据而不前移文件位置。 至少将返回一个字节的数据,除非已经到达 EOF。 实际返回的字节数不确定(会忽略 size 参数)。

备注

调用 peek() 不会改变 ZstdFile 的文件位置,但它可能会改变底层文件对象的位置(例如,如果 ZstdFile 是通过传递一个文件对象作为 file 参数来构造的)。

mode

'rb' 用于读取而 'wb' 用于写入。

name

Zstandard 文件的名称。等同于底层 file objectname 属性。

在内存中压缩和解压缩数据

compression.zstd.compress(data, level=None, options=None, zstd_dict=None)

压缩 data (一个 bytes-like object),返回压缩后的数据作为一个 bytes 对象。

level 参数是一个控制压缩级别的整数。level 是设置 optionsCompressionParameter.compression_level 的替代方案。使用 compression_level 上的 bounds() 方法获取可以传递给 level 的值。如果需要高级压缩选项,必须省略 level 参数,并在 options 字典中设置 CompressionParameter.compression_level 参数。

options 参数是一个包含高级压缩参数的 Python 字典。压缩参数的有效键和值在 CompressionParameter 文档中有说明。

zstd_dict 参数是一个 ZstdDict 实例,包含训练数据以提升压缩效率。可以使用 train_dict() 函数生成一个 Zstandard 字典。

compression.zstd.decompress(data, zstd_dict=None, options=None)

解压缩 data (一个 bytes-like object),返回解压缩后的数据作为一个 bytes 对象。

options 参数是一个包含高级解压缩参数的 Python 字典。解压缩参数的有效键和值在 DecompressionParameter 文档中有说明。

zstd_dict 参数是一个 ZstdDict 实例,包含在压缩过程中使用的训练数据。这必须是与压缩时使用的相同的 Zstandard 字典。

如果 data 参数是由多个独立压缩帧拼接而成的数据,则会解压所有这些帧,并返回解压结果的拼接串。

class compression.zstd.ZstdCompressor(level=None, options=None, zstd_dict=None)

创建一个压缩器对象,此对象可被用来执行增量压缩。

有关压缩单个数据块的更便捷方法,请参阅模块级函数 compress()

level 参数是一个控制压缩级别的整数。level 是设置 optionsCompressionParameter.compression_level 的替代方案。使用 compression_level 上的 bounds() 方法获取可以传递给 level 的值。如果需要高级压缩选项,必须省略 level 参数,并在 options 字典中设置 CompressionParameter.compression_level 参数。

options 参数是一个包含高级压缩参数的 Python 字典。压缩参数的有效键和值在 CompressionParameter 文档中有说明。

zstd_dict 参数是可选的 ZstdDict 实例,包含训练数据以改进压缩效率。可以使用函数 train_dict() 生成 Zstandard 字典。

compress(data, mode=ZstdCompressor.CONTINUE)

压缩 data (一个 bytes-like object),如果可能,返回包含压缩数据的 bytes 对象,否则返回一个空的 bytes 对象。data 的一部分可能会在内部缓冲,用于后续调用 compress()flush()。返回的数据应与之前任何对 compress() 的调用的输出连接起来。

mode 参数是 ZstdCompressor 属性,可以是 CONTINUEFLUSH_BLOCKFLUSH_FRAME

当所有数据都已提供给压缩器时,调用 flush() 方法以完成压缩过程。如果 compress() 被调用且 mode 设置为 FLUSH_FRAME,则不应调用 flush(),因为它会写入一个新的空帧。

flush(mode=ZstdCompressor.FLUSH_FRAME)

结束压缩进程,返回包含保存在压缩器的内部缓冲区中的任意数据的 bytes 对象。

mode 参数是 ZstdCompressor 属性,可以是 FLUSH_BLOCKFLUSH_FRAME

set_pledged_input_size(size)

指定将为下一个帧提供的未压缩数据 size。除非 CompressionParameter.content_size_flagFalse0,否则 size 将写入下一个帧的帧头。大小为 0 表示帧为空。如果 sizeNone,帧头将省略帧大小。包含未压缩数据大小的帧在解压缩时需要更少的内存,尤其是在更高的压缩级别下。

如果 last_mode 不是 FLUSH_FRAME,则会引发 ValueError,因为压缩器未处于帧的开始位置。如果承诺的大小与提供给 compress() 的实际数据大小不匹配,未来的对 compress()flush() 的调用可能会引发 ZstdError,并且最后一个数据块可能会丢失。

在以 FLUSH_FRAME 模式调用 flush()compress() 后,除非再次调用 set_pledged_input_size(),否则下一个帧的头部将不包括帧大小。

CONTINUE

收集更多数据进行压缩,这可能立即生成输出,也可能不立即生成。此模式通过最大化每个块和帧的数据量来优化压缩率。

FLUSH_BLOCK

完成并写入一个块到数据流。至此返回的数据可以立即解压缩。过去的数据仍然可以在通过调用 compress() 生成的未来块中被引用,从而提高压缩效果。

FLUSH_FRAME

完成并写出帧。提供给 compress() 的未来数据将被写入新帧,并且 不能 引用过去的数据。

last_mode

最后一个传递给 compress()flush() 的模式。值可以是 CONTINUEFLUSH_BLOCKFLUSH_FRAME。初始值为 FLUSH_FRAME,表示压缩器处于新帧的开始位置。

class compression.zstd.ZstdDecompressor(zstd_dict=None, options=None)

创建一个压缩器对象,此对象可被用来执行增量解压缩。

要一次性解压缩整个压缩流,请参阅模块级函数 decompress()

options 参数是一个包含高级解压缩参数的 Python 字典。解压缩参数的有效键和值在 DecompressionParameter 文档中有说明。

zstd_dict 参数是一个 ZstdDict 实例,包含在压缩过程中使用的训练数据。这必须是与压缩时使用的相同的 Zstandard 字典。

备注

此类不会透明化处理包含多个压缩帧的输入,与 decompress() 函数和 ZstdFile 类不同。要解压缩多帧输入,您应使用 decompress(),如果处理的是 file object,则使用 ZstdFile 类,或者使用多个 ZstdDecompressor 实例分别处理。

decompress(data, max_length=-1)

解压缩 data (一个 bytes-like object),返回未压缩的数据作为字节。部分 data 可能会在内部缓冲,以便在后续调用 decompress() 时使用。返回的数据应与之前调用 decompress() 的输出连接起来。

如果 max_length 参数为非负值,该方法最多返回 max_length 字节的解压数据。当达到此限制但仍有可输出数据时,needs_input 属性将被设为 False。此时,下次调用 decompress() 方法时可传入 datab'' 以获取更多输出数据。

如果所有输入数据都已被解压缩并返回(或是因为它少于 max_length 个字节,或是因为 max_length 为负数),则 needs_input 属性将被设为 True

尝试在帧结束后解压缩数据将引发 ZstdError。帧结束后的任何数据将被忽略并保存在 unused_data 属性中。

eof

若达到了数据流的末尾标记则为 True

unused_data

在压缩数据流的末尾之后获取的数据。

在达到流的末尾之前,这将始终为 b''

needs_input

如果 decompress() 方法在需要新的压缩输入之前可以提供更多解压缩数据,则为 False

Zstandard 字典

compression.zstd.train_dict(samples, dict_size)

训练一个 Zstandard 字典,返回一个 ZstdDict 实例。Zstandard 字典能够更有效地压缩较小规模的数据,这些数据由于重复较少而传统上难以压缩。如果您正在压缩多个相似的数据组(例如相似文件),Zstandard 字典可以显著提高压缩率和速度。

参数 samples (一个 bytes 对象的可迭代对象) 是用于训练 Zstandard 字典的样本集。

参数 dict_size,一个整数,是 Zstandard 字典应达到的最大大小(以字节为单位)。Zstandard 文档建议绝对最大值不超过 100 KB,但最大值通常取决于数据,可能会更小。较大的字典通常会减慢压缩速度,但提高压缩率。较小的字典导致更快的压缩,但降低压缩率。

compression.zstd.finalize_dict(zstd_dict, /, samples, dict_size, level)

一个高级函数,用于将“原始内容”Zstandard字典转换为常规Zstandard字典。“原始内容”字典是一系列字节,不需要遵循正常Zstandard字典的结构。

zstd_dict 参数是一个 ZstdDict 实例,其 dict_content 包含原始字典内容。

samples 参数(一个 bytes 对象的可迭代集合),包含用于生成Zstandard字典的样本数据。

dict_size 参数,一个整数,是Zstandard字典应达到的最大大小(以字节为单位)。参见 train_dict() 以获取关于最大字典大小的建议。

level 参数(一个整数)是预期传递给使用此字典的压缩器的压缩级别。每个压缩级别的字典信息不同,因此针对适当的压缩级别进行调整可以使压缩更高效。

class compression.zstd.ZstdDict(dict_content, /, *, is_raw=False)

Zstandard字典的包装器。字典可用于提高许多小数据块的压缩效果。如果需要从样本数据训练新字典,请使用 train_dict()

dict_content 参数 (一个 bytes-like object),是已经训练好的字典信息。

is_raw 参数,一个布尔值,是一个高级参数,控制 dict_content 的含义。True 表示 dict_content 是一个“原始内容”字典,没有任何格式限制。False 表示 dict_content 是一个普通的Zstandard字典,由Zstandard函数例如 train_dict() ,或外部 zstd CLI创建。

当将一个 ZstdDict 传递给函数时,可以通过传递 as_digested_dictas_undigested_dict 属性作为``zstd_dict``参数来控制字典的加载方式,例如,compress(data, zstd_dict=zd.as_digested_dict)。消化字典是一个成本较高的操作,它在加载Zstandard字典时发生。在进行多次压缩或解压缩调用时,传递已消化的字典将减少加载字典的开销。

压缩差异

已消化字典

未消化字典

压缩器的高级参数,可能会被字典的参数覆盖

window_log, hash_log, chain_log, search_log, min_match, target_length, strategy, enable_long_distance_matching, ldm_hash_log, ldm_min_match, ldm_bucket_size_log, ldm_hash_rate_log,以及一些非公开参数。

None

ZstdDict 类会在内部缓存字典数据。

是的。在再次加载相同压缩级别的已消化字典时,速度更快。

否。如果希望多次加载未消化字典,考虑重用压缩器对象。

如果传递一个不带任何属性的:class:!ZstdDict,则在压缩时默认传递未消化字典,在解压缩时如果需要会生成并默认传递已消化字典。

dict_content

Zstandard字典的内容,一个 bytes 对象。它与 __init__ 方法中的 dict_content 参数相同。它可以与其他程序一起使用,例如 zstd CLI程序。

dict_id

Zstandard字典的标识符,一个非负整数值。

非零表示字典是普通的,由Zstandard函数创建并遵循Zstandard格式。

0 表示一个“原始内容”字典,没有任何格式限制,供高级用户使用。

备注

对于 ZstdDict.dict_id0 的含义与 get_frame_info() 函数的 dictionary_id 属性不同。

as_digested_dict

作为已消化的字典加载。

as_undigested_dict

作为未消化的字典加载。

高级参数控制

class compression.zstd.CompressionParameter

一个 IntEnum,包含在压缩数据时可以使用的高级压缩参数键。

可以使用 bounds() 方法在任何属性上获取该参数的有效值。

参数是可选的;任何省略的参数将自动选择其值。

获取 compression_level 的下界和上界的示例:

lower, upper = CompressionParameter.compression_level.bounds()

window_log 设置为最大值的示例:

_lower, upper = CompressionParameter.window_log.bounds()
options = {CompressionParameter.window_log: upper}
compress(b'venezuelan beaver cheese', options=options)
bounds()

返回压缩参数的整型边界元组 (lower, upper)。此方法应调用在你希望获取边界的属性上。例如,要获取 compression_level 的有效值,可以检查 CompressionParameter.compression_level.bounds() 的结果。

下界和上界都是包含在内的。

compression_level

一种高级方法,用于设置其他影响数据压缩速度和比例的压缩参数。

常规压缩等级需大于 0。当等级值超过 20 时,将被视为"极致"压缩级别,该级别需要比其他等级消耗更多内存。负数值可用于以牺牲压缩率为代价换取更快的压缩速度。

将级别设置为零使用 COMPRESSION_LEVEL_DEFAULT

window_log

压缩器在压缩数据时可以使用的最大允许后向引用距离,表示为二的幂,1 << window_log 字节。此参数极大地影响压缩的内存使用。更高的值需要更多内存,但可以获得更好的压缩值。

值为零会导致自动选择该值。

hash_log

初始探测表的大小为2的幂次方。实际内存占用为 1 << (hash_log+2) 字节。较大的探测表能提升 <= dfast 策略的压缩率,并加快 > dfast 策略的压缩速度。

值为零会导致自动选择该值。

chain_log

多探测搜索表的大小,以2的幂表示。由此产生的内存使用量为 1 << (chain_log+2) 字节。较大的表会导致更好的但更慢的压缩。此参数对 fast 策略无效。在使用 dfast 策略时仍然有用,在这种情况下,它定义了一个二级探测表。

值为零会导致自动选择该值。

search_log

搜索尝试的次数,以2的幂表示。更多的尝试会导致更好的但更慢的压缩。此参数对 fastdfast 策略无用。

值为零会导致自动选择该值。

min_match

搜索匹配的最小大小。较大的值会增加压缩和解压速度,但会降低压缩率。请注意,Zstandard 仍然可以找到较小大小的匹配,它只是调整其搜索算法以查找此大小及更大的匹配。对于所有策略 < btopt,有效最小值为 4;对于所有策略 > fast,有效最大值为 6

值为零会导致自动选择该值。

target_length

此字段的影响取决于所选的 Strategy

对于策略 btoptbtultrabtultra2,该值被视为“足够好”的匹配长度以停止搜索。较大的值会提高压缩率,但压缩速度较慢。

对于策略 fast,它是匹配采样的间隔距离。较大的值会使压缩更快,但压缩率较差。

值为零会导致自动选择该值。

strategy

所选策略的值越高,zstd 使用的压缩技术越复杂,导致压缩率更高但压缩速度更慢。

参见

Strategy

enable_long_distance_matching

长距离匹配可以通过在更远距离找到大匹配来提高大输入的压缩效果。这会增加内存使用和窗口大小。

True1 启用长距离匹配,而 False0 禁用长距离匹配。

启用此参数会将默认的 window_log 增加到 128 MiB,除非明确设置为其他值。如果 window_log >= 128 MiB 且压缩策略 >= btopt (压缩级别 16+),此设置默认启用。

ldm_hash_log

长距离匹配表的尺寸,以二的幂表示。较大的值会增加内存使用和压缩率,但会降低压缩速度。

值为零会导致自动选择该值。

ldm_min_match

长距离匹配器的最小匹配大小。过大或过小的值通常会降低压缩率。

值为零会导致自动选择该值。

ldm_bucket_size_log

长距离匹配器哈希表中每个桶的日志大小,用于冲突解决。较大的值会改善冲突解决,但会降低压缩速度。

值为零会导致自动选择该值。

ldm_hash_rate_log

向长距离匹配器哈希表插入/查找条目的频率。较大的值会提高压缩速度。偏离默认值过远可能会降低压缩率。

值为零会导致自动选择该值。

content_size_flag

若在压缩前已知待压缩数据的大小,则将该数据大小写入Zstandard帧头。

此标志仅在以下情况下生效:

所有其他压缩调用可能不会将大小信息写入帧头。

True1 启用内容大小标志,而 False0 禁用它。

checksum_flag

使用 XXHash64 的四字节校验和写入每个帧的末尾。Zstandard 的解压缩代码会验证校验和。如果校验和不匹配,则会引发 ZstdError 异常。

True1 启用校验和生成,而 False0 禁用它。

dict_id_flag

使用 ZstdDict 压缩时,字典的 ID 会被写入帧头部。

True1 启用存储字典 ID,而 False0 禁用它。

nb_workers

选择将启动多少线程以并行压缩。当 nb_workers > 0 时,启用多线程压缩,值为 1 表示“单线程多线程模式”。更多工作线程可以提高速度,但也会增加内存使用并略微降低压缩率。

值为零禁用多线程。

job_size

压缩任务的大小,以字节为单位。此值仅在 nb_workers >= 1 时生效。每个压缩任务并行完成,因此此值可以间接影响活动线程的数量。

值为零会导致自动选择该值。

overlap_log

设置压缩过程中,新任务可从先前任务(线程)重新加载多少数据供后向参考窗口使用。该参数仅在 nb_workers ≥ 1 时生效。有效取值范围为0到9。

  • 0 表示动态设置重叠量。

  • 1 表示无重叠。

  • 9 表示使用上一个任务的全窗口大小。

每个增量将重叠大小减半/加倍。“8”表示重叠 window_size/2“,“7”表示重叠 ``window_size/4,等等。

class compression.zstd.DecompressionParameter

一个包含高级解压缩参数键的 IntEnum,这些参数键在解压缩数据时可以使用。参数是可选的;任何省略的参数将自动选择其值。

可以使用 bounds() 方法在任何属性上获取该参数的有效值。

例如,将 window_log_max 设置为最大大小:

data = compress(b'一些非常长的字节缓冲区...')

_lower, upper = DecompressionParameter.window_log_max.bounds()

options = {DecompressionParameter.window_log_max: upper}
decompress(data, options=options)
bounds()

返回解压缩参数的整型边界元组 (lower, upper)。此方法应调用在您希望检索边界的属性上。

下界和上界都是包含在内的。

window_log_max

解压缩期间使用的最大窗口大小的二进制对数。这有助于限制解压缩数据时使用的内存量。较大的最大窗口大小会导致更快的解压缩。

值为零会导致自动选择该值。

class compression.zstd.Strategy

一个包含压缩策略的 IntEnum。编号较高的策略对应更复杂和更慢的压缩。

备注

Strategy 属性的值在不同版本的 zstd 中不一定稳定。只能依赖属性的顺序。以下按顺序列出属性。

以下策略可用:

fast
dfast
greedy
lazy
lazy2
btlazy2
btopt
btultra
btultra2

杂项

compression.zstd.get_frame_info(frame_buffer)

检索包含有关 Zstandard 帧元数据的 FrameInfo 对象。帧包含与其持有的压缩数据相关的元数据。

class compression.zstd.FrameInfo

与 Zstandard 帧相关的元数据。

decompressed_size

帧中解压缩内容的大小。

dictionary_id

表示解压缩帧所需的 Zstandard 字典 ID 的整数。0 表示字典 ID 未记录在帧头中。这可能意味着不需要 Zstandard 字典,或者所需的字典 ID 未记录。

compression.zstd.COMPRESSION_LEVEL_DEFAULT

Zstandard 的默认压缩级别:3

compression.zstd.zstd_version_info

运行时 zstd 库的版本号,作为整数元组 (major, minor, release)。

例子

读取压缩文件:

from compression import zstd

with zstd.open("file.zst") as f:
    file_content = f.read()

创建压缩文件:

from compression import zstd

data = b"在此插入数据"
with zstd.open("file.zst", "w") as f:
    f.write(data)

在内存中压缩数据:

from compression import zstd

data_in = b"在此插入数据"
data_out = zstd.compress(data_in)

增量压缩:

from compression import zstd

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

写入已压缩数据到一个已打开的文件:

from compression import zstd

with open("myfile", "wb") as f:
    f.write(b"该数据将不会被压缩。\n")
    with zstd.open(f, "w") as zstf:
        zstf.write(b"这 *将会* 被压缩\n")
    f.write(b"没有被压缩\n")

使用压缩形参创建一个已压缩文件:

from compression import zstd

options = {
   zstd.CompressionParameter.checksum_flag: 1
}
with zstd.open("file.zst", "w", options=options) as f:
    f.write(b"请问现在方便插入(操作/请求)吗?")