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 — будь-який об’єкт, подібний до потоку, наприклад файл, сокет або потік (зокрема io.BytesIO). Сам є потоком і реалізує стандартні методи read/readinto/write/close.

stream має бути блокуючим потоком. Неблокуючі потоки наразі не підтримуються.

Параметр format може приймати будь-яке зі значень констант, визначених нижче, і за замовчуванням дорівнює AUTO: при розпакуванні автоматично визначає формат gzip або zlib, а при стисненні генерує «сирий» потік.

Параметр wbits задає двійковий логарифм розміру вікна словника DEFLATE. Наприклад, встановлення wbits у 10 задає розмір вікна 1024 байти. Допустимі значення від 5 до 15 включно (відповідають розмірам вікна від 32 до 32768 байт).

Якщо wbits встановлено у 0 (за замовчуванням), то при стисненні буде використано вікно розміром 256 байт (як ніби wbits встановлено у 8). При розпакуванні поведінка залежить від формату:

  • RAW використовуватиме 256 байт (що відповідає wbits = 8).

  • ZLIB (або AUTO з виявленим zlib) використовуватиме значення із заголовка zlib.

  • GZIP (або AUTO з виявленим gzip) використовуватиме 32 кілобайти (що відповідає wbits = 15).

Докладніше про розмір вікна, zlib та gzip-потоки — у примітці window size нижче.

Якщо close встановлено у True, базовий потік буде автоматично закрито при закритті потоку deflate.DeflateIO. Це зручно, коли потрібно повернути потік deflate.DeflateIO, що обгортає інший потік, і не навантажувати виклику необхідністю керувати базовим потоком.

Якщо стиснення увімкнено, конкретний екземпляр deflate.DeflateIO підтримує як читання, так і запис. Наприклад, можна обгорнути двонаправлений потік, такий як сокет, що дозволяє виконувати стиснення/розпакування в обох напрямках.

Константи

Чотири константи format визначають обрамлення навколо «сирого» бітового потоку deflate.

deflate.AUTO: int

При розпакуванні автоматично визначає вхідний формат, аналізуючи перші байти потоку (zlib або gzip). При стисненні генерує «сирий» потік deflate без заголовка та трейлера (еквівалентно RAW).

deflate.RAW: int

«Сирий» потік deflate (без заголовка, трейлера та контрольної суми). Оскільки потік не містить метаданих, декомпресор не може відновити розмір вікна з даних, тому при розпакуванні wbits слід задавати явно — інакше вікно за замовчуванням 256 байт може бути замалим.

deflate.ZLIB: int

Потік deflate у форматі zlib, як визначено RFC 1950: 2-байтний заголовок із записом розміру вікна, корисне навантаження deflate та кінцева контрольна сума Adler-32. Компактний і самоописовий; добре підходить для вбудованих систем.

deflate.GZIP: int

Потік deflate у форматі gzip, як визначено RFC 1952: заголовок із необов’язковими метаданими (ім’я файлу/мітка часу), корисне навантаження deflate та кінцеві CRC-32 і нестиснена довжина. Це формат, який генерує утиліта gzip та gzip.GzipFile. Заголовок не містить розміру вікна, тому декомпресор повинен припускати 32 КіБ, якщо wbits не задано.

Приклади

Типовий випадок використання 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 або реалізація gzip.GzipFile в CPython) використовують максимальний розмір вікна 32 КіБ. З цієї причини, якщо параметр wbits не задано, декомпресор використовуватиме вікно 32 КіБ (що відповідає wbits = 15). Це означає, що для розпакування довільного gzip-потоку необхідно мати щонайменше стільки оперативної пам’яті. Якщо ви контролюєте джерело даних, розгляньте використання формату zlib із меншим розміром вікна.

Формат raw не містить заголовка і тому не включає жодної інформації про розмір вікна. Якщо wbits не задано, за замовчуванням буде використано вікно 256 байт, якого може бути недостатньо для конкретного потоку. Тому рекомендується завжди явно задавати wbits при використанні raw-формату.

Стиснення

При стисненні MicroPython за замовчуванням використовує вікно 256 байт для всіх форматів. Це забезпечує розумний ступінь стиснення при мінімальному використанні пам’яті та швидкому часі стиснення, і генерує вихідні дані, сумісні з будь-яким декомпресором.