Poměrně často potřebuje člověk pracovat s daty v nějakém komprimovaném formátu. Ať už se jedná o soubory (či celé adresářové struktury) zabalené pomocí taru či gzipu nebo třebas o obrazová data uvnitř PNG-obrázku.
Python poskytuje ve standardní knihovně podporu pro několik komprimačních formátů – konkrétně zip, gzip, bz2, lzma a tar. Snad nejhezčí na tom všem je, že s archívy se pracuje téměř úplně stejně snadno jako s obyčejnými soubory.
Z podporovaných je formát ZIP asi nejrozšířenější mezi různými platformami, začneme proto od něj. V principu se skládá ze dvou částí:
Vzhledem k výchozímu nastavení parametrů je ve většině případů komprimace a dekomprimace binárních dat velmi jednoduchá záležitost:
Součástí formátu ZIP je i výpočet kontrolního součtu nad zadanými daty. Knihovna zlib obsahuje dvě metody:
PS: Ani jedna z těchto metod není samozřejmě vůbec vhodná pro výpočet hashů, natožpak dokonce pro kryptografii.
Pokud byste byli nuceni pracovat s daty, která by se vám nevlezla najednou do paměti, obsahuje knihovna zlib metody zlib.compressobj() a zlib.decompressobj() se spoustou možností nastavení.
Uvedené metody vrací objekty, které podporují (případnou částečnou) komprimaci a dekomprimaci nad zadanými (binárními) daty. Jednoduchý příklad:
Zde použitá data jsou samozřejmě příliš krátká, aby to celé dávalo rozumný smysl. Pro další metody a jejich použití viz originální dokumentace.
Komprimace pomocí klasického ZIPu není sice zdaleka tak účinná jako jiné (novější) metody, ale narozdíl od většiny jiných se s daty v archívu pracuje velmi snadno – „zabalíte-li“ více souborů (nebo rovnou adresářů), je každý jednotlivý prvek přístupný nezávisle na ostatních.
Knihovna zipfile slouží jako rozhraní pro komprimaci/dekomprimaci i u formátů bzip2 a LZMA, kteréžto se staly součástí standardu ZIP v letech 2001, respektive 2006.
Základním objektem pro práci se ZIP-archívy je zipfile.ZipFile. Pomocí něj získáte přístup k již existujícím i nově vytvářeným zip-archívům. Samozřejmostí je použití uvnitř kontextového manažeru, tedy:
Objekt typu ZipFile je možno zavést s různými parametry podle typu práce, který vás čeká, a také na něm podle toho volat různé metody.
Plný konstruktor objektu typu ZipFile jest..
zipfile.ZipFile( file, mode='r', compression=ZIP_STORED, allowZip64=True )
..což znamená, že se otevírá existující zip-archív pro čtení a je zapnuta podpora pro archívy větší než 2 GB.
Podle typu otevření souboru archívu získáte následující vlastnosti:
Otevřený ZipFile-objekt poskytuje všechny své metody nezávisle na způsobu otevření, což znamená, že pokusíte-li se zavolat například ZipFile.write()
na archívu otevřeném jako 'r', se zlou se potážete (konkrétně obdržíte výjimku RuntimeError).
Typy komprimace jsou podporovány následující čtyři:
Všimněte si především, že výchozím nastavením je zipfile.ZIP_STORED, tedy práce se zip-archívy bez komprimace. To se může hodit, pokud je třeba poskytnout data v adresářové struktuře v rámci jednoho zip-archívu, ale není třeba (nebo není z výpočetních důvodů možno) objem dat zmenšovat. Typicky to asi ale nebude to, co budete chtít – z hlediska přenositelnosti mezi různými operačními systémy je nejvhodnější volbou asi klasický původní zipfile.ZIP_DEFLATED.
Jeden soubor do archívu přidává metoda ZipFile-objektu write(SOUBOR)
:
Její chování můžete upravit pomocí dalších dvou nepovinných parametrů:
arcname
– jméno použité pro archivovaný soubor uvnitř archívu;
compress_type
– změna typu komprese oproti globálnímu zadání (ZipFile(compression)).
Obzvláště arcname nalezne své uplatnění, nebudou-li cesty k archivovaným souborům zadány relativně (což je ale nepřekvapivě doporučováno).
Jelikož zipfile umí jako nejvyšší jednotku zabalit jeden konkrétní soubor, musíme si pro zabalení adresáře (v příkladu jím jest adresář data) trochu pomoci. Následuje skript předpokládající idealizovaný stav, kdy je adresář k zabalení na stejné úrovni souborového systému jako vlastní skript:
Ne vždy je však možné doporučený požadavek relativnosti cest rozumně dodržet. Pak se nám právě hodí parametr arcname:
Velmi zajímavou možností je posílat do archívu řetězce a „pouze“ jim určit, pod jakým souborovým jménem se v něm mají uložit. K tomu slouží metoda ZipFile-objektu:
writestr(zinfo_or_arcname, ŘETĚZEC)
Důležitým je zde první parametr metody zinfo_or_arcname, který právě určuje, kde řetězcová data skončí. Kromě obyčejného řetězce (určujícího cestu uvnitř archívu stejně jako dříve představený parametr arcname) jím totiž může také být instance objektu zipfile.ZipInfo, který zjednodušeně řečeno drží metadata jednotlivých souborů uvnitř archívu.
Máme-li naopak již existující archív, můžeme se o něm spoustu věcí dozvědět, aniž bychom ho rozbalovali:
Test archívu pomocí ZipFile.testzip()
:
Pro neporušený archív vrátí None, pro porušený jméno prvního souboru v archívu, u kterého selhala kontrola (kontrola CRC a hlavičky).
Obsah archívu přehledně pomocí ZipFile.printdir()
:
Pouze jména souborů pomocí ZipFile.namelist()
:
Informace o souborech v archívu se také dají získat jako objekty typu zipfile.ZipInfo. Máme přitom dvě možnosti – pro všechny soubory najednou nebo pro jeden konkrétní.
Informace o jednotlivých souborech pomocí ZipFile.infolist()
:
Informace o jednotlivých souborech pomocí ZipFile.getinfo(CESTA)
:
Data z jednoho konkrétního souboru v archívu můžeme přečíst pomocí metody ZipFile.read(CESTA, pwd=None)
:
Data jsou vrácena jako bajtový řetězec. Mají-li představovat text, rozkódovat si je musíte sami.
Další možností, jak se k datům v archívu dostat, je jednoduše je „rozbalit“ na disk. Jde to buď pro jeden soubor (extract(PRVEK, path=None, pwd=None)
) nebo pro všechny (extractall(path=None, members=None, pwd=None)
).
Přestože se knihovna zipfile snaží případné absolutní i relativní cesty osekat na zcela místní (a také odstraňuje pro danou platformu neznámé znaky), vřele se NEdoporučuje bezhlavě rozbalovat cizí archívy bez kontroly jejich obsahu!
Obě metody umožňují změnit místo extrakce z aktuálního adresáře na jiný pomocí parametru path a také případně přenastavit heslo (parametr pwd). Metodu extractall() je navíc možno doplnit o podseznam seznamu souborů v archívu vráceného metodou ZipFile.namelist().
Jeden konkrétní soubor:
Vybraných vícero souborů:
Knihovna zipfile toho umí víc (mimo jiné připisovat až 64 kB dlouhé komentáře k archívům pomocí parametru ZipFile.comment
nebo balit archívy pythoních zdrojových souborů).
Podobně ZipInfo
objekty obsahují spoustu zajímavých informací, především:
Pro základní práci uvedené však ale snad stačí.