deflate – DEFLATE 压缩 & 解压

该模块允许使用 DEFLATE 算法 (通常用于 zlib 库和 gzip 压缩器)对二进制数据进行压缩和解压缩。

可用性:

  • 在 MicroPython v1.21 中添加。

  • 解压缩: 通过 MICROPY_PY_DEFLATE 构建选项启用,默认情况下在具有 “extra features “ 级别或更高级别的移植版本上启用(大多数开发板)。

  • 压缩: 通过 MICROPY_PY_DEFLATE_COMPRESS 构建选项启用,默认情况下在具有 “full features” 级别或更高级别的移植版本上启用(通常这意味着您需要构建自己的固件以启用此功能)。

class deflate.DeflateIO(stream, format=AUTO, wbits=0, close=False, /)

这个类可以用来包装一个 stream,它是任何 stream-like 对象,比如文件、套接字或流(包括 io.BytesIO)。它本身是一个流,并实现了标准的read/readinto/write/close 方法。

stream 必须是一个阻塞流。非阻塞流目前不受支持。

format 可以设置为下面定义的任何常量,默认为 AUTO,对于解压缩,它将自动检测 gzip 或 zlib 流,对于压缩,它将生成一个原始流。

wbits 参数设置了 DEFLATE 字典窗口大小的以 2 为底的对数。例如,将 *wbits*设置为 10 ,将窗口大小设置为 1024 字节。有效值为 515 (包括)(对应窗口大小为 32 到 32k 字节)。

如果 wbits 设置为 0 (默认值),则对于压缩,将使用 256 字节的窗口大小(就好像 wbits 设置为 8)。对于解压缩,它取决于格式:

  • RAW 将使用 256 字节(对应 wbits 设置为 8)。

  • ZLIB (或检测到 zlib 的 AUTO)将使用 zlib 标头中的值。

  • GZIP (或检测到 gzip 的 AUTO)将使用 32 千字节(对应 wbits 设置为 15)。

查看下面关于窗口大小、zlib 和 gzip 流的 window size 注意事项,获取更多信息。

如果 close 设置为 True,那么在关闭 deflate.DeflateIO 流时将自动关闭底层流。如果您希望返回一个包装另一个流的 deflate.DeflateIO 流,并且不希望调用者知道如何管理底层流,这是有用的。

如果启用了压缩,给定的 deflate.DeflateIO 实例支持读和写。例如,可以包装一个双向流(如套接字),这样就可以在两个方向上进行压缩/解压缩。

常量

deflate.AUTO
deflate.RAW
deflate.ZLIB
deflate.GZIP

format 参数支持的值。

示例

deflate.DeflateIO 的典型用例是从存储中读取或写入压缩文件:

import deflate

# Writing a zlib-compressed stream (uses the default window size of 256 bytes).
with open("data.gz", "wb") as f:
    with deflate.DeflateIO(f, deflate.ZLIB) as d:
        # Use d.write(...) etc

# Reading a zlib-compressed stream (auto-detect window size).
with open("data.z", "rb") as f:
    with deflate.DeflateIO(f, deflate.ZLIB) as d:
        # Use d.read(), d.readinto(), etc.

因为 deflate.DeflateIO 是一个流,所以它可以与 json.dump()json.load() (以及任何其他可以使用流的地方)一起使用:

import deflate, json

# Write a dictionary as JSON in gzip format, with a
# small (64 byte) window size.
config = { ... }
with open("config.gz", "wb") as f:
    with deflate.DeflateIO(f, deflate.GZIP, 6) as f:
        json.dump(config, f)

# Read back that dictionary.
with open("config.gz", "rb") as f:
    with deflate.DeflateIO(f, deflate.GZIP, 6) as f:
        config = json.load(f)

如果您的源数据不是流格式,可以使用 io.BytesIO 将其转换为适合与 deflate.DeflateIO: 一起使用的流:

import deflate, io

# Decompress a bytes/bytearray value.
compressed_data = get_data_z()
with deflate.DeflateIO(io.BytesIO(compressed_data), deflate.ZLIB) as d:
    decompressed_data = d.read()

# Compress a bytes/bytearray value.
uncompressed_data = get_data()
stream = io.BytesIO()
with deflate.DeflateIO(stream, deflate.ZLIB) as d:
    d.write(uncompressed_data)
compressed_data = stream.getvalue()

DEFLATE 窗口大小

窗口大小限制了(解)压缩器在流中可以引用的距离。增加窗口大小将提高压缩率,但会需要更多内存,并使压缩器变慢。

如果输入流被压缩到了给定的窗口大小,那么使用较小窗口大小的 DeflateIO 在解压缩过程中会在中途失败,抛出 OSError,但仅当后向引用实际上超出了解压缩器的窗口大小时。这意味着可能可以使用较小的窗口大小解压缩。例如,如果原始未压缩数据比窗口大小短,则这显然是可能的。

解压缩

zlib 格式包括一个头,指定了用于压缩数据的窗口大小。这表示解压缩此流所需的最大窗口大小。如果此头值小于指定的 wbits 值(或 wbits 未设置),则将使用头值。

gzip 格式不在头中包括窗口大小,并假定所有 gzip 压缩器(例如 gzip 实用程序或 CPython 的 gzip.GzipFile 实现)使用 32kiB 的最大窗口大小。因此,如果 wbits 参数未设置,则解压缩器将使用 32 kiB 的窗口大小(对应 wbits 设置为 15)。这意味着为了能够解压缩任意 gzip 流,您必须至少有这么多 RAM 可用。如果您控制源数据,考虑使用 zlib 格式并使用较小的窗口大小。

原始格式没有头,因此不包括有关窗口大小的任何信息。如果未设置 wbits,则默认使用256 字节的窗口大小,这可能对于给定的流来说不够大。因此,建议如果使用原始格式,应始终明确设置 wbits

压缩

对于压缩,MicroPython 将默认为所有格式使用 256 字节的窗口大小。这提供了合理的压缩量,内存使用量小,压缩时间快,并且生成的输出可以与任何解压缩器一起使用。