deflate — kompresja i dekompresja deflate

Ten moduł umożliwia kompresję i dekompresję danych binarnych za pomocą algorytmu DEFLATE (powszechnie używanego w bibliotece zlib oraz archiwizatorze gzip). Dodany w MicroPython v1.21.

Dostępność na płytkach obsługiwanych przez OpenMV:

Płytka

Dekompresja

Kompresja

OpenMV Cam N6

Tak

Nie

OpenMV AE3

Tak

Tak

OpenMV Cam RT1062

Tak

Tak

OpenMV Cam Pure Thermal

Tak

Nie

OpenMV Cam M4

Tak

Nie

OpenMV Cam M7

Tak

Nie

OpenMV Cam H7

Tak

Nie

OpenMV Cam H7 Plus

Tak

Nie

Arduino Giga

Tak

Nie

Arduino Portenta H7

Tak

Nie

Arduino Nicla Vision

Tak

Nie

Arduino Nano 33 BLE Sense

Tak

Nie

Arduino Nano RP2040 Connect

Tak

Nie

Klasy

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

Tej klasy można użyć do opakowania stream, czyli dowolnego obiektu przypominającego strumień, takiego jak plik, gniazdo lub strumień (w tym io.BytesIO). Sama jest strumieniem i implementuje standardowe metody read/readinto/write/close.

stream musi być strumieniem blokującym. Strumienie nieblokujące nie są obecnie obsługiwane.

format można ustawić na dowolną ze stałych zdefiniowanych poniżej; domyślnie ma wartość AUTO, która przy dekompresji automatycznie wykrywa strumienie gzip lub zlib, a przy kompresji generuje strumień surowy.

Parametr wbits ustawia logarytm o podstawie 2 z rozmiaru okna słownika DEFLATE. Na przykład ustawienie wbits na 10 ustawia rozmiar okna na 1024 bajty. Prawidłowe wartości to od 5 do 15 włącznie (odpowiadające rozmiarom okna od 32 do 32k bajtów).

Jeśli wbits zostanie ustawione na 0 (wartość domyślna), to przy kompresji zostanie użyty rozmiar okna 256 bajtów (tak jakby wbits ustawiono na 8). Przy dekompresji zależy to od formatu:

  • RAW użyje 256 bajtów (odpowiadających wbits ustawionemu na 8).

  • ZLIB (lub AUTO z wykrytym zlib) użyje wartości z nagłówka zlib.

  • GZIP (lub AUTO z wykrytym gzip) użyje 32 kilobajtów (odpowiadających wbits ustawionemu na 15).

Więcej informacji o rozmiarze okna oraz strumieniach zlib i gzip można znaleźć w uwagach o rozmiarze okna poniżej.

Jeśli close zostanie ustawione na True, to bazowy strumień zostanie automatycznie zamknięty wraz z zamknięciem strumienia deflate.DeflateIO. Jest to przydatne, gdy chcesz zwrócić strumień deflate.DeflateIO opakowujący inny strumień, tak aby wywołujący nie musiał zajmować się zarządzaniem bazowym strumieniem.

Jeśli kompresja jest włączona, dana instancja deflate.DeflateIO obsługuje zarówno odczyt, jak i zapis. Na przykład można opakować strumień dwukierunkowy, taki jak gniazdo, co umożliwia kompresję/dekompresję w obu kierunkach.

Stałe

Cztery stałe format wybierają ramkowanie nakładane wokół surowego strumienia bitów deflate.

deflate.AUTO: int

Przy dekompresji automatycznie wykrywa format danych wejściowych, sprawdzając pierwsze bajty strumienia (zlib lub gzip). Przy kompresji generuje surowy strumień deflate bez nagłówka i stopki (równoważnie do RAW).

deflate.RAW: int

Surowy strumień deflate (bez nagłówka, bez stopki, bez sumy kontrolnej). Ponieważ strumień nie zawiera żadnych metadanych, dekompresor nie może odzyskać rozmiaru okna z danych, więc przy dekompresji należy jawnie ustawić wbits – w przeciwnym razie domyślne okno 256 bajtów może być zbyt małe.

deflate.ZLIB: int

Strumień deflate opakowany w zlib, zgodny z definicją RFC 1950: 2-bajtowy nagłówek zapisujący rozmiar okna, ładunek deflate oraz końcowa suma kontrolna Adler-32. Zwarty i samoopisujący się; dobrze nadaje się do zastosowań wbudowanych.

deflate.GZIP: int

Strumień deflate opakowany w gzip, zgodny z definicją RFC 1952: nagłówek z opcjonalnymi metadanymi nazwy pliku/znacznika czasu, ładunek deflate oraz końcowa suma kontrolna CRC-32 wraz z długością nieskompresowaną. Jest to format generowany przez narzędzie wiersza poleceń gzip oraz przez gzip.GzipFile. Nagłówek nie zapisuje rozmiaru okna, więc dekompresor musi przyjąć 32 KiB, chyba że ustawiono wbits.

Przykłady

Typowym przypadkiem użycia deflate.DeflateIO jest odczyt lub zapis skompresowanego pliku z pamięci masowej:

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.

Ponieważ deflate.DeflateIO jest strumieniem, można go używać na przykład z json.dump() i json.load() (oraz w każdym innym miejscu, gdzie można używać strumieni):

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)

Jeśli Twoje dane źródłowe nie są w formacie strumienia, możesz użyć io.BytesIO, aby zamienić je w strumień odpowiedni do użycia z 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()

Rozmiar okna deflate

Rozmiar okna ogranicza, jak daleko wstecz w strumieniu (de)kompresor może się odwoływać. Zwiększenie rozmiaru okna poprawi kompresję, ale będzie wymagało więcej pamięci i spowolni kompresor.

Jeśli strumień wejściowy został skompresowany z danym rozmiarem okna, to DeflateIO używające mniejszego rozmiaru okna zakończy się niepowodzeniem w trakcie dekompresji z błędem OSError, ale tylko wtedy, gdy odwołanie wsteczne faktycznie sięga dalej niż rozmiar okna dekompresora. Oznacza to, że może być możliwa dekompresja przy mniejszym rozmiarze okna. Na przykład będzie tak w sposób oczywisty, gdy oryginalne nieskompresowane dane są krótsze niż rozmiar okna.

Dekompresja

Format zlib zawiera nagłówek określający rozmiar okna użyty do kompresji danych. Wskazuje to maksymalny rozmiar okna wymagany do dekompresji tego strumienia. Jeśli ta wartość z nagłówka jest mniejsza niż podana wartość wbits (lub jeśli wbits nie jest ustawione), to zostanie użyta wartość z nagłówka.

Format gzip nie zawiera rozmiaru okna w nagłówku i zakłada, że wszystkie kompresory gzip (np. narzędzie gzip lub implementacja gzip.GzipFile w CPythonie) używają maksymalnego rozmiaru okna 32kiB. Z tego powodu, jeśli parametr wbits nie jest ustawiony, dekompresor użyje rozmiaru okna 32 kiB (odpowiadającego wbits ustawionemu na 15). Oznacza to, że aby móc zdekompresować dowolny strumień gzip, musisz mieć dostępną co najmniej taką ilość pamięci RAM. Jeśli kontrolujesz dane źródłowe, rozważ zamiast tego użycie formatu zlib z mniejszym rozmiarem okna.

Format surowy nie ma nagłówka i dlatego nie zawiera żadnych informacji o rozmiarze okna. Jeśli wbits nie jest ustawione, to domyślnie przyjmie rozmiar okna 256 bajtów, który może nie być wystarczająco duży dla danego strumienia. Dlatego zaleca się, abyś przy używaniu formatu surowego zawsze jawnie ustawiał wbits.

Kompresja

Przy kompresji MicroPython domyślnie przyjmie rozmiar okna 256 bajtów dla wszystkich formatów. Zapewnia to rozsądny poziom kompresji przy minimalnym zużyciu pamięci i krótkim czasie kompresji oraz generuje wynik, który będzie działał z dowolnym dekompresorem.