zipfile - Accede a un Archivio ZIP
Scopo: Legge e scrive file compressi ZIP
Il modulo zipfile può essere usato per manipolare file di archivio ZIP, il formato reso popolare dal programma per pc PKZIP.
Verificare file ZIP
La funzione is_zipfile()
ritorna un booleano che indica se il nome di file passato come argomento faccia riferimento o meno a un archivio ZIP valido.
# zipfile_is_zipfile.py
import zipfile
for filename in [ 'LEGGIMI.txt', 'esempio.zip',
'cattivo_esempio.zip', 'nonqui.zip' ]:
print('{:>20} {}'.format(
filename, zipfile.is_zipfile(filename)))
Se il file non esiste, is_zipfile()
ritorna False
.
$ python3 zipfile_is_zipfile.py LEGGIMI.txt False esempio.zip True cattivo_esempio.zip False nonqui.zip False
Leggere i Metadati da un Archivio
Si usi la classe Zipfile
per lavorare direttamente con un archivio ZIP. Essa supporta sia metodi per leggere dati riguardo archivi esistenti che per modificare gli archivi aggiungendo file.
# zipfile_namelist.py
import zipfile
with zipfile.ZipFile('esempio.zip', 'r') as zf:
print(zf.namelist())
Il metodo namelist()
ritorna i nomi dei file di un archivio esistente.
$ python3 zipfile_namelist.py ['LEGGIMI.txt']
L'elenco di nomi è l'unica parte di informazioni disponibili dall'archivio. Per accedere a tutti i metadati circa il contenuto dello ZIP si usino i metodi infolist()
oppure getinfo()
.
# zipfile_infolist.py
import datetime
import zipfile
def print_info(archive_name):
with zipfile.ZipFile(archive_name) as zf:
for info in zf.infolist():
print(info.filename)
print(' Commento :', info.comment)
mod_date = datetime.datetime(*info.date_time)
print(' Modificato :', mod_date)
if info.create_system == 0:
system = 'Windows'
elif info.create_system == 3:
system = 'Unix'
else:
system = 'SCONOSCIUTO'
print(' Sistema :', system)
print(' Versione ZIP :', info.create_version)
print(' Compressi :', info.compress_size, 'byte')
print(' Non compressi:', info.file_size, 'byte')
print()
if __name__ == '__main__':
print_info('esempio.zip')
Ci sono campi addizionali, oltre a quelli stampati qui, ma trascodificare i valori in qualcosa che abbia una qualsiasi utilità richiede una attenta lettura delle note dell'applicazione PKZIP con le specifiche del file ZIP.
$ python3 zipfile_infolist.py LEGGIMI.txt Commento : b'' Modificato : 2018-07-29 10:25:20 Sistema : Unix Versione ZIP : 63 Compressi : 56 byte Non compressi: 61 byte
Se il nome del membro di un archivio è noto in anticipo, è possibile ricavare un oggetto ZipInfo
direttamente tramite getinfo()
.
# zipfile_getinfo.py
import zipfile
with zipfile.ZipFile('esempio.zip') as zf:
for filename in ['LEGGIMI.txt', 'nonqui.txt']:
try:
info = zf.getinfo(filename)
except KeyError:
print('ERRORE: Non trovato {} nel file zip'.format(
filename))
else:
print('{} è {} byte'.format(
info.filename, info.file_size))
Se un membro di archivio non è presente, getinfo()
solleva una eccezione.
$ python3 zipfile_getinfo.py LEGGIMI.txt è 61 byte ERRORE: Non trovato nonqui.txt nel file zip
Estrarre File da un Archivio
Per accedere ai dati di un membro di un archivio, si usi il metodo read()
, passando il nome del membro.
# zipfile_read.py
import zipfile
with zipfile.ZipFile('esempio.zip') as zf:
for filename in ['LEGGIMI.txt', 'nonqui.txt']:
try:
data = zf.read(filename)
except KeyError:
print('ERRORE: Non trovato {} nel file zip'.format(
filename))
else:
print(filename, ':')
print(data)
print()
I dati, se necessario, sono automaticamente decompressi.
$ python3 zipfile_read.py LEGGIMI.txt : b'Gli esempi per i moduli zipfile e tarfile usano questo file.\n' ERRORE: Non trovato nonqui.txt nel file zip
Creare Nuovi Archivi
Per creare un nuovo archivio, si istanzi ZipFile
con modalità 'w'
. Qualunque file esistente verrà troncato e verrà inizializzato un nuovo archivio. Per aggiungere file si usi il metodo write()
.
# zipfile_write.py
from zipfile_infolist import print_info
import zipfile
print('creazione archivio')
with zipfile.ZipFile('write.zip', mode='w') as zf:
print('aggiungo LEGGIMI.txt')
zf.write('LEGGIMI.txt')
print()
print_info('write.zip')
Nella modalità predefinita, i contenuti dell'archivio non sono compressi.
$ python3 zipfile_write.py creazione archivio aggiungo LEGGIMI.txt LEGGIMI.txt Commento : b'' Modificato : 2018-07-29 10:23:42 Sistema : Unix Versione ZIP : 20 Compressi : 61 byte Non compressi: 61 byte
Per aggiungere compressione, è richiesto il modulo zlib. Se zlib è disponibile, la modalità di compressione per i singoli file o per l'intero archivio può essere impostata usando zipfile.ZIP_DEFLATED
. La modalità di compressione predefinita è zipfile_ZIP_STORED
, che aggiunge file all'archivio senza comprimerli.
# zipfile_write_compression.py
from zipfile_infolist import print_info
import zipfile
try:
import zlib
compression = zipfile.ZIP_DEFLATED
except (ImportError, AttributeError):
compression = zipfile.ZIP_STORED
modes = {
zipfile.ZIP_DEFLATED: 'compresso',
zipfile.ZIP_STORED: 'conservato',
}
print('creazione archivio')
with zipfile.ZipFile('write_compression.zip', mode='w') as zf:
mode_name = modes[compression]
print('aggiungo LEGGIMI.txt con modalità compressione', mode_name)
zf.write('LEGGIMI.txt', compress_type=compression)
print()
print_info('write_compression.zip')
In questo caso, il membro dell'archivio è compresso.
$ python3 zipfile_write_compression.py creazione archivio aggiungo LEGGIMI.txt con modalità compressione compresso LEGGIMI.txt Commento : b'' Modificato : 2018-07-29 10:23:42 Sistema : Unix Versione ZIP : 20 Compressi : 56 byte Non compressi: 61 byte
Usare Nomi di Membri di Archivio Sostitutivi
Per aggiungere un file a un archivio usando un nome diverso da quello originale si usi l'argomento arcname
per write()
.
# zipfile_write_arcname.py
from zipfile_infolist import print_info
import zipfile
with zipfile.ZipFile('write_arcname.zip', mode='w') as zf:
zf.write('LEGGIMI.txt', arcname='NON_LEGGIMI.txt')
print_info('write_arcname.zip')
Non vi è traccia del nome file originale nell'archivio.
$ python3 zipfile_write_arcname.py NON_LEGGIMI.txt Commento : b'' Modificato : 2018-07-29 10:23:42 Sistema : Unix Versione ZIP : 20 Compressi : 61 byte Non compressi: 61 byte
Scrivere Dati da Sorgenti Diverse da File
Talvolta è necessario scrivere verso un archivio ZIP usando dati che non provengono da un file esistente. Piuttosto che scrivere dati a un file, quindi aggiungere lo stesso al file ZIP, si usi il metodo writestr()
che aggiunge una stringa di byte all'archivio direttamente.
# zipfile_writestr.py
from zipfile_infolist import print_info
import zipfile
msg = 'Questi dati non esistono in un file.'
with zipfile.ZipFile('writestr.zip',
mode='w',
compression=zipfile.ZIP_DEFLATED,
) as zf:
zf.writestr('da_una_stringa.txt', msg)
print_info('writestr.zip')
with zipfile.ZipFile('writestr.zip', 'r') as zf:
print(zf.read('da_una_stringa.txt'))
In questo caso, l'argomento compress_type
di ZipFile
è stato usato per comprimere i dati visto che writestr()
non prevede un argomento che specifichi la compressione.
$ python3 zipfile_writestr.py da_una_stringa.txt Commento : b'' Modificato : 2021-06-03 09:16:42 Sistema : Unix Versione ZIP : 20 Compressi : 36 byte Non compressi: 36 byte b'Questi dati non esistono in un file.'
Scrivere con una Istanza di ZipInfo
Normalmente la data di modifica viene calcolata quando un file o una stringa vengono aggiunti all'archivio. Una istanza di ZipInfo
può essere passata a writestr()
per definire la data di modifica e altri metadati.
# zipfile_writestr_zipinfo.py
import time
import zipfile
from zipfile_infolist import print_info
msg = b'Questi dati non esistono in un file.'
with zipfile.ZipFile('writestr_zipinfo.zip',
mode='w',
) as zf:
info = zipfile.ZipInfo('da_stringa.txt',
date_time=time.localtime(time.time()),
)
info.compress_type = zipfile.ZIP_DEFLATED
info.comment = b'I commenti vanno qui'
info.create_system = 0
zf.writestr(info, msg)
print_info('writestr_zipinfo.zip')
In questo esempio, l'orario modificato viene impostato all'orario corrente, i dati sono compressi, e viene usato un valore False
per create_system
. Viene anche associato un semplice commento al nuovo file.
$ python3 zipfile_writestr_zipinfo.py da_stringa.txt Commento : b'I commenti vanno qui' Modificato : 2021-06-03 09:16:42 Sistema : Windows Versione ZIP : 20 Compressi : 36 byte Non compressi: 36 byte
Aggiungere File
Oltre alla creazione di nuovi archivi, è possibile aggiungere in un archivio esistente, oppure aggiungere un archivio a un file esistente (tipo un file a.exe
per un archivio auto estraente). Per aprire un archivio per aggiungere un file si usi la modalità 'a'
.
# zipfile_append.py
from zipfile_infolist import print_info
import zipfile
print('creazione archivio')
with zipfile.ZipFile('append.zip', mode='w') as zf:
zf.write('LEGGIMI.txt')
print()
print_info('append.zip')
print("aggiungo all'archivio")
with zipfile.ZipFile('append.zip', mode='a') as zf:
zf.write('LEGGIMI.txt', arcname='LEGGIMI2.txt')
print()
print_info('append.zip')
L'archivio risultante contiene due membri:
$ python3 zipfile_append.py creazione archivio LEGGIMI.txt Commento : b'' Modificato : 2018-07-29 10:23:42 Sistema : Unix Versione ZIP : 20 Compressi : 61 byte Non compressi: 61 byte aggiungo all'archivio LEGGIMI.txt Commento : b'' Modificato : 2018-07-29 10:23:42 Sistema : Unix Versione ZIP : 20 Compressi : 61 byte Non compressi: 61 byte LEGGIMI2.txt Commento : b'' Modificato : 2018-07-29 10:23:42 Sistema : Unix Versione ZIP : 20 Compressi : 61 byte Non compressi: 61 byte
Archivi ZIP Python
Python può importare moduli all'interno di un file ZIP usando zipimport, se questi archivi sono in sys.path
. La classe PyZipFile
può essere usata per costruire un modulo adatto per l'utilizzo con questa modalità. Il metodo supplementare writepy()
dice a PyZipFile
di cercare file con suffisso .py
nella directory e aggiungere i corrispondenti file con estensione .pyo
o .pyc
all'archivio. Se nessuna delle forme compilate esiste, file creato e aggiunto un file .pyc
.
# zipfile_pyzipfile.py
import sys
import zipfile
if __name__ == '__main__':
with zipfile.PyZipFile('pyzipfile.zip', mode='w') as zf:
zf.debug = 3
print('Aggiungo file python')
zf.writepy('./zipfile')
for name in zf.namelist():
print(name)
print()
sys.path.insert(0, 'pyzipfile.zip')
import zipfile_pyzipfile
print('Importati da:', zipfile_pyzipfile.__file__)
Con l'attributo di debut di PyZipFile
impostato a 3, viene abilitato un debug verboso e il risultato viene prodotto mentre compile ogni file .py
che trova.
$ python3 zipfile_pyzipfile.py Aggiungo file python Adding files from directory ./zipfile Adding zipfile_append.pyc Adding zipfile_getinfo.pyc Adding zipfile_infolist.pyc Adding zipfile_is_zipfile.pyc Adding zipfile_namelist.pyc Adding zipfile_pyzipfile.pyc Adding zipfile_read.pyc Adding zipfile_write.pyc Adding zipfile_write_arcname.pyc Adding zipfile_write_compression.pyc Adding zipfile_writestr.pyc Adding zipfile_writestr_zipinfo.pyc zipfile_append.pyc zipfile_getinfo.pyc zipfile_infolist.pyc zipfile_is_zipfile.pyc zipfile_namelist.pyc zipfile_pyzipfile.pyc zipfile_read.pyc zipfile_write.pyc zipfile_write_arcname.pyc zipfile_write_compression.pyc zipfile_writestr.pyc zipfile_writestr_zipinfo.pyc Importati da: pyzipfile.zip/zipfile_pyzipfile.pyc
Limitazioni
Il modulo zipfile non supporta file ZIP con commenti aggiunti, o archivi multi disco. Supporta file ZIP più grandi di 4 GB che usano le estensioni ZIP64.