Scrierea și citirea fișierelor de arhivă ZIP
Formatul ZIP este cel mai popular format de arhivare și compresie a fișierelor. Limbajul Python include un modul încorporat pentru lucrul cu acest tip de fișiere - zipfile. Cu ajutorul acestui modul, putem crea, citi, scrie fișiere ZIP, obține conținutul acestora și adăuga fișiere noi în arhivă. De asemenea, modulul suportă criptarea fișierelor, dar nu suportă decriptarea acestora.
Pentru a reprezenta un fișier ZIP, modulul definește clasa ZipFile. Aceasta are următorul constructor:
ZipFile(file, mode='r', compression=ZIP_STORED, allowZip64=True, compresslevel=None, *, strict_timestamps=True, metadata_encoding=None)
Parametri:
- file: calea către fișierul ZIP
- mode: modul de deschidere a fișierului. Poate avea următoarele valori: - r: pentru citirea unui fișier existent. - w: pentru scrierea unui fișier nou. - a: pentru adăugarea de fișiere într-un fișier existent
- compression: tipul de compresie utilizat la scrierea fișierului. Poate avea valori precum: - ZIP_STORED: arhivare fără compresie (valoare implicită). - ZIP_DEFLATED: tipul standard de compresie ZIP. - ZIP_BZIP2: compresie utilizând metoda BZIP2. - ZIP_LZMA: compresie utilizând metoda LZMA
- allowZip64: dacă este True, permite ca fișierul ZIP să fie mai mare de 4 GB
- сompresslevel: nivelul de compresie la scrierea fișierului. Nu se aplică pentru tipurile de compresie ZIP_STORED și ZIP_LZMA. Pentru ZIP_DEFLATED, valorile permise sunt de la 0 la 9, iar pentru ZIP_BZIP2, de la 1 la 9
- strict_timestamps: la False, permite lucrul cu fișiere ZIP create înainte de 01.01.1980 și după 31.12.2107
- metadata_encoding: utilizat pentru decodarea metadatelor fișierului ZIP (de exemplu, comentarii)
Clasa ZipFile oferă o serie de metode pentru lucrul cu fișiere:
- close(): închide fișierul ZIP
- getinfo(): returnează informații despre un fișier din arhivă sub forma unui obiect ZipInfo
- namelist(): returnează o listă cu numele fișierelor din arhivă
- infolist(): returnează informații despre toate fișierele din arhivă sub forma unei liste de obiecte ZipInfo
- open(): oferă acces la unul dintre fișierele din arhivă
- read(): citește un fișier din arhivă sub formă de octeți
- extract(): extrage un fișier din arhivă
- extractall(): extrage toate elementele din arhivă
- setpassword(): stabilește o parolă pentru fișierul ZIP
- printdir(): afișează pe consolă conținutul arhivei
Crearea și închiderea unui fișier ZIP
Pentru a crea un fișier ZIP, în constructorul ZipFile se transmite modul w sau a:
from zipfile import ZipFile
myzip = ZipFile("fdc.zip", "w")
După executarea acestui cod, în folderul curent va fi creat un fișier ZIP gol numit "fdc.zip".
După ce am terminat lucrul cu arhiva, trebuie să o închidem folosind metoda close():
from zipfile import ZipFile
myzip = ZipFile("fdc.zip", "w")
myzip.close()
Deoarece ZipFile suportă context managerul, putem folosi instrucțiunea with, care va închide automat fișierul la finalizarea contextului:
from zipfile import ZipFile
with ZipFile("fdc.zip", "w") as myzip:
pass
Scrierea fișierelor în arhivă
Pentru a scrie fișiere în arhivă, se utilizează metoda write():
write(filename, arcname=None, compress_type=None, compresslevel=None)
Primul parametru reprezintă fișierul care va fi adăugat în arhivă. Al doilea parametru, arcname, permite setarea unui nume arbitrar pentru fișierul din arhivă (implicit, este folosit numele fișierului original). Al treilea parametru, compress_type, specifică tipul de compresie, iar compresslevel specifică nivelul de compresie.
De exemplu, să adăugăm fișierul "hello.txt" în arhiva "fdc.zip":
from zipfile import ZipFile
with ZipFile("fdc.zip", "w") as myzip:
myzip.write("hello.txt")
Este important de reținut că, atunci când deschidem fișierul ZIP în modul "w", orice conținut anterior este suprascris. Dacă dorim să adăugăm fișiere într-un fișier ZIP existent, trebuie să deschidem fișierul în modul "a":
from zipfile import ZipFile
with ZipFile("fdc.zip", "a") as myzip:
myzip.write("hello2.txt")
myzip.write("forest.jpg")
Implicit, compresia nu este aplicată. Dacă dorim să aplicăm o metodă de compresie și un nivel de compresie, putem specifica acești parametri:
from zipfile import ZipFile, ZIP_DEFLATED
with ZipFile("fdc.zip", "w", compression=ZIP_DEFLATED, compresslevel=3) as myzip:
myzip.write("hello.txt")
Dacă încercăm să adăugăm în arhivă fișiere cu nume deja existente, consola va afișa un avertisment. Pentru a evita conflictele de nume, putem specifica un nume unic pentru fișierele din arhivă folosind al doilea parametru al metodei write:
from zipfile import ZipFile
with ZipFile("fdc.zip", "a") as myzip:
myzip.write("hello.txt", "hello1.txt")
myzip.write("hello.txt", "hello2.txt")
myzip.write("hello.txt", "hello3.txt")
Obținerea informațiilor despre fișierele din arhivă
Metoda infolist() returnează informații despre fișierele din arhivă sub formă de listă, unde fiecare fișier este reprezentat de un obiect ZipInfo:
from zipfile import ZipFile
with ZipFile("fdc.zip", "a") as myzip:
print(myzip.infolist())
Clasa ZipInfo oferă o serie de atribute pentru stocarea informațiilor despre fișier. Cele mai importante sunt:
- filename: numele fișierului
- ate_time: data și ora ultimei modificări a fișierului sub forma unui tuplu în formatul (an, lună, zi, oră, minut, secundă)
- compress_type: tipul de compresie
- compress_size: dimensiunea după compresie
- file_size: dimensiunea originală a fișierului înainte de compresie
Putem obține aceste date pentru fiecare fișier din arhivă:
from zipfile import ZipFile
with ZipFile("fdc.zip", "r") as myzip:
for item in myzip.infolist():
print(f"File Name: {item.filename} Date: {item.date_time} Size: {item.file_size}")
Ieșirea pe consolă ar putea arăta astfel:
File Name: hello.txt Date: (2022, 11, 23, 20, 21, 34) Size: 18
File Name: forest.jpg Date: (2022, 11, 19, 20, 46, 52) Size: 103956
File Name: hello1.txt Date: (2022, 11, 23, 20, 21, 34) Size: 18
File Name: hello2.txt Date: (2022, 11, 23, 20, 21, 34) Size: 18
File Name: hello3.txt Date: (2022, 11, 23, 20, 21, 34) Size: 18
Cu ajutorul metodei is_dir() putem verifica dacă un element din arhivă este un folder:
from zipfile import ZipFile
with ZipFile("fdc.zip", "r") as myzip:
for item in myzip.infolist():
if item.is_dir():
print(f"Folder: {item.filename}")
else:
print(f"File: {item.filename}")
Pentru a obține doar lista de nume ale fișierelor din arhivă, putem folosi metoda namelist():
from zipfile import ZipFile
with ZipFile("fdc.zip", "r") as myzip:
for item in myzip.namelist():
print(item)
Ieșirea pe consolă ar putea fi:
hello.txt
forest.jpg
hello1.txt
hello2.txt
hello3.txt
Cu ajutorul metodei getinfo(), putem obține date despre un anumit fișier arhivat, transmițând numele acestuia în arhivă ca parametru. Rezultatul metodei este un obiect ZipInfo:
from zipfile import ZipFile
with ZipFile("fdc.zip", "r") as myzip:
try:
hello_file = myzip.getinfo("hello.txt")
print(hello_file.file_size)
except KeyError:
print("Fișierul specificat nu există")
Dacă elementul cu numele specificat nu este găsit în arhivă, metoda va genera o excepție KeyError.
Extracția fișierelor din arhivă
Pentru a extrage toate fișierele din arhivă, se folosește metoda extractall():
extractall(path=None, members=None, pwd=None)
Primul parametru al metodei specifică directorul în care se vor extrage fișierele (implicit, se extrag în directorul curent). Parametrul members reprezintă o listă de șiruri - lista de nume ale fișierelor care trebuie extrase din arhivă. Al treilea parametru, pwd, reprezintă parola în cazul în care arhiva este protejată cu parolă.
De exemplu, pentru a extrage toate fișierele din arhivă:
from zipfile import ZipFile
with ZipFile("fdc.zip", "r") as myzip:
myzip.extractall()
Extracția într-un folder specific:
myzip.extractall(path="fdc")
Extracția unui subset de fișiere:
# extragem fișierele "hello.txt", "forest.jpg" în folderul "fdc2"
myzip.extractall(path="fdc2", members=["hello.txt", "forest.jpg"])
Pentru a extrage un singur fișier, se folosește metoda extract(), căreia i se transmite numele fișierului care trebuie extras:
myzip.extract("hello.txt")
Citirea unui fișier
Metoda read() permite citirea conținutului unui fișier din arhivă sub formă de octeți:
from zipfile import ZipFile
with ZipFile("fdc.zip", "r") as myzip:
content = myzip.read("hello5.txt")
print(content)
Deschiderea unui fișier
Metoda open() permite deschiderea fișierelor din arhivă fără a le extrage efectiv:
open(name, mode='r', pwd=None, *, force_zip64=False)
Primul parametru obligatoriu este numele fișierului din arhivă. Al doilea parametru, mode, stabilește modul de deschidere. Parametrul pwd specifică parola, dacă fișierul este protejat. Parametrul force_zip64, la True, permite deschiderea fișierelor mai mari de 4 GB.
Această metodă este utilă pentru manipularea fișierelor, de exemplu, pentru citirea conținutului sau, dimpotrivă, pentru scrierea acestora. De exemplu, să deschidem un fișier și să citim conținutul acestuia:
from zipfile import ZipFile
with ZipFile("fdc.zip", "a") as myzip:
# scriem un nou fișier "hello5.txt" în arhivă
with myzip.open("hello5.txt", "w") as hello_file:
encoded_str = bytes("Python...", "UTF-8")
hello_file.write(encoded_str)