deflate --- deflate 壓縮與解壓縮#
此模組允許使用 DEFLATE 演算法(常用於 zlib 函式庫與 gzip 壓縮工具)對二進位資料進行壓縮與解壓縮。在 MicroPython v1.21 中新增。
在 OpenMV 支援的板子上的可用性:
板子 | 解壓縮 | 壓縮 |
|---|---|---|
OpenMV Cam N6 | 是 | 否 |
OpenMV AE3 | 是 | 是 |
OpenMV Cam RT1062 | 是 | 是 |
OpenMV Cam Pure Thermal | 是 | 否 |
OpenMV Cam M4 | 是 | 否 |
OpenMV Cam M7 | 是 | 否 |
OpenMV Cam H7 | 是 | 否 |
OpenMV Cam H7 Plus | 是 | 否 |
Arduino Giga | 是 | 否 |
Arduino Portenta H7 | 是 | 否 |
Arduino Nicla Vision | 是 | 否 |
Arduino Nano 33 BLE Sense | 是 | 否 |
Arduino Nano RP2040 Connect | 是 | 否 |
類別#
- class deflate.DeflateIO(stream: Any, format: int = AUTO, wbits: int = 0, close: bool = False, /)#
此類別可用於包裝一個 stream,它是任何 類串流 物件,例如檔案、socket 或串流(包括
io.BytesIO)。它本身即為串流,並實作標準的 read/readinto/write/close 方法。stream 必須是阻塞式串流。目前不支援非阻塞式串流。
format 可設為下方定義的任一常數,預設為
AUTO;解壓縮時它會自動偵測 gzip 或 zlib 串流,壓縮時則會產生原始串流。wbits 參數設定 DEFLATE 字典視窗大小以 2 為底的對數。因此,例如將 wbits 設為
10會將視窗大小設為 1024 位元組。有效值為5至15(含)(對應 32 至 32k 位元組的視窗大小)。若 wbits 設為
0(預設值),則壓縮時會使用 256 位元組的視窗大小(如同 wbits 設為 8)。解壓縮時則視格式而定:RAW將使用 256 位元組(對應 wbits 設為 8)。ZLIB(或偵測到 zlib 的AUTO)將使用 zlib 標頭中的值。GZIP(或偵測到 gzip 的AUTO)將使用 32 千位元組(對應 wbits 設為 15)。
如需更多關於視窗大小、zlib 與 gzip 串流的資訊,請參閱下方的 視窗大小 說明。
若 close 設為
True,則當deflate.DeflateIO串流關閉時,底層串流也會自動關閉。如果你想傳回一個包裝了另一個串流的deflate.DeflateIO串流,又不希望呼叫者需要知道如何管理底層串流,這會很有用。若啟用了壓縮,則給定的
deflate.DeflateIO實例同時支援讀取與寫入。例如,可以包裝像 socket 這樣的雙向串流,從而允許在兩個方向上進行壓縮/解壓縮。
常數#
這四個 format 常數用於選擇套用於原始 deflate 位元串流外圍的框架格式。
- deflate.RAW: int#
原始的 deflate 串流(無標頭、無結尾、無檢查碼)。由於串流不含任何中介資料,解壓縮器無法從資料中還原視窗大小,因此解壓縮時應明確設定 wbits——否則預設的 256 位元組視窗可能太小。
- deflate.ZLIB: int#
如 RFC 1950 所定義、以 zlib 包裝的 deflate 串流:一個記錄視窗大小的 2 位元組標頭、deflate 酬載,以及結尾的 Adler-32 檢查碼。精簡且具自我描述性;非常適合嵌入式使用。
- deflate.GZIP: int#
如 RFC 1952 所定義、以 gzip 包裝的 deflate 串流:一個含選用檔名/時間戳記中介資料的標頭、deflate 酬載,以及結尾的 CRC-32 加上未壓縮長度。這是
gzip命令列工具與gzip.GzipFile所產生的格式。標頭不記錄視窗大小,因此除非設定了 wbits,否則解壓縮器必須假設為 32 KiB。
範例#
deflate.DeflateIO 的典型使用情境是從儲存裝置讀取或寫入壓縮檔案:
import deflate
# Writing a zlib-compressed stream (uses the default window size of 256 bytes).
with open("data.z", "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 格式。
raw 格式沒有標頭,因此不包含任何關於視窗大小的資訊。若未設定 wbits,則會預設為 256 位元組的視窗大小,這對特定串流而言可能不夠大。因此,若使用 raw 格式,建議你務必明確設定 wbits。
壓縮#
壓縮時,MicroPython 對所有格式都會預設為 256 位元組的視窗大小。這在最少的記憶體使用量與快速的壓縮時間下提供合理程度的壓縮,並會產生可與任何解壓縮器搭配運作的輸出。