zipfile - Leggere e scrivere file di archivio ZIP

Scopo Leggere e scrivere file di archivio ZIP.
Versione Python 1.6 e successive

Il modulo zipfile può essere usato per manipolare file di archivio ZIP.

Limitazioni

Il modulo zipfile non supporta i file ZIP con commenti aggiunti, oppure file ZIP su dischi multipli. Supporta i file ZIP superiori a 4 GB che usano le estensioni ZIP64.

Verificare i File ZIP

La funzione is_zipfile() restituisce un valore booleano che indica se il nome del file passato come parametro faccia riferimento o meno ad un file ZIP valido.

import zipfile

for filename in [ 'LEGGIMI.txt', 'esempio.zip',
                  'cattivo_esempio.zip', 'nonqui.zip' ]:
    print '%20s  %s' % (filename, zipfile.is_zipfile(filename))

Si noti che se il file non esiste, is_zipfile() restituisce False.

$ python zipfile_is_zipfile.py
         LEGGIMI.txt  False
         esempio.zip  True
 cattivo_esempio.zip  False
          nonqui.zip  False

Leggere Meta-dati da un Archivio ZIP

Per lavorare direttamente con un archivio ZIP si usa la classe ZipFile. Essa supporta metodi per leggere dati su archivi esistenti così come per la modifica di archivi aggiungendo ulteriori file.

Per leggere i nomi dei file in un archivio esistente si usa namelist().

import zipfile

zf = zipfile.ZipFile('esempio.zip', 'r')
print zf.namelist()

Il valore di ritorno è una lista di stringhe con i nomi del contenuto dell'archivio.

$ python zipfile_namelist.py
['LEGGIMI.txt']

L'elenco dei nomi è solo parte delle informazioni disponibili dall'archivio. Per accedere a tutti i meta-dati riguardo al contenuto di uno ZIP is usano i metodi infolist() o getinfo().

import datetime
import zipfile

def print_info(archive_name):
    zf = zipfile.ZipFile(archive_name)
    for info in zf.infolist():
        print info.filename
        print '\tCommento:\t', info.comment
        print '\tModificato:\t', datetime.datetime(*info.date_time)
        print '\tSistema:\t', info.create_system, '(0 = Windows, 3 = Unix)'
        print '\tversione ZIP:\t', info.create_version
        print '\tCompressi:\t', info.compress_size, 'byte'
        print '\tNon compressi:\t', info.file_size, 'byte'
        print

if __name__ == '__main__':
    print_info('esempio.zip')

Ci sono campi addizionali oltre a quelli stampati qui sotto, ma il decifrare i valori in qualche cosa che sia utile richiede una attenta lettura delle Note Applicative PKZIP con le specifiche del file ZIP.

$ python zipfile_infolist.py
LEGGIMI.txt
	Commento:
	Modificato:	2010-03-16 21:15:58
	Sistema:	3 (0 = Windows, 3 = Unix)
	versione ZIP:	30
	Compressi:	67 byte
	Non compressi:	77 byte

Se si conosce in anticipo il nome del membro dell'archivio si può ottenere il suo oggetto Zipinfo con getinfo().

import zipfile

zf = zipfile.ZipFile('esempio.zip')
for filename in [ 'LEGGIMI.txt', 'nonqui.txt' ]:
    try:
        info = zf.getinfo(filename)
    except KeyError:
        print 'ERRORE: Non trovato %s nel file zip' % filename
    else:
        print '%s è di %d byte' % (info.filename, info.file_size)

Se il membro dell'archivio non è presente, getinfo() solleva un KeyError.

$ python zipfile_getinfo.py
LEGGIMI.txt è di 77 byte
ERRORE: Non trovato nonqui.txt nel file zip

Estrarre File Archiviati da un Archivio ZIP

Per accedere ai dati da un membro di un archivio, si usa il metodo read(), passandogli il nome del membro.

import zipfile

zf = zipfile.ZipFile('esempio.zip')
for filename in [ 'LEGGIMI.txt', 'nonqui.txt' ]:
    try:
        data = zf.read(filename)
    except KeyError:
        print 'ERRORE: Non trovato %s nel file zip' % filename
    else:
        print filename, ':'
        print repr(data)
    print

Se necessario, i dati vengono automaticamente decompressi.

$ python zipfile_read.py
LEGGIMI.txt :
'Gli esempi per il modulo tarfile usano questo file ed esempio.zip come dati.\n'

ERRORE: Non trovato nonqui.txt nel file zip

Creare Nuovi Archivi

Per creare un nuovo archivio, si istanzia semplicemente ZipFile in modalità 'w'. Un qualsiasi file esistente viene troncato e viene creato un nuovo archivio. Per aggiungere dei file si usa il metodo write().

from zipfile_infolist import print_info
import zipfile

print 'creazione archivio'
zf = zipfile.ZipFile('zipfile_write.zip', mode='w')
try:
    print 'aggiungo LEGGIMI.txt'
    zf.write('LEGGIMI.txt')
finally:
    print 'chiusura'
    zf.close()

print
print_info('zipfile_write.zip')

Nella modalità predefinita, il contenuto dell'archivio non viene compresso.

$ python zipfile_write.py
creazione archivio
aggiungo LEGGIMI.txt
chiusura

LEGGIMI.txt
	Commento:
	Modificato:	2010-03-16 21:15:58
	Sistema:	3 (0 = Windows, 3 = Unix)
	versione ZIP:	20
	Compressi:	77 byte
	Non compressi:	77 byte

Per aggiungere la compressione, è richiesto il modulo zlib. Se zlib è disponibile, si può impostare la modalità di compressione per singolo file o per l'intero archivio usando zipfile.ZIP_DEFLATED. La modalità di compressione predefinita è zipfile.ZIP_STORED

from zipfile_infolist import print_info
import zipfile
try:
    import zlib
    compression = zipfile.ZIP_DEFLATED
except:
    compression = zipfile.ZIP_STORED

modes = { zipfile.ZIP_DEFLATED: 'compresso',
          zipfile.ZIP_STORED:   'archiviato',
          }

print 'creazione archivio'
zf = zipfile.ZipFile('zipfile_write_compression.zip', mode='w')
try:
    print 'aggiunta di LEGGIMI.txt con modalità di compressione', modes[compression]
    zf.write('LEGGIMI.txt', compress_type=compression)
finally:
    print 'chiusura'
    zf.close()

print
print_info('zipfile_write_compression.zip')

Questa volta l'archivio viene compresso

$ python zipfile_write_compression.py
creazione archivio
aggiunta di LEGGIMI.txt con modalità di compressione compresso
chiusura

LEGGIMI.txt
	Commento:
	Modificato:	2010-03-16 21:15:58
	Sistema:	3 (0 = Windows, 3 = Unix)
	versione ZIP:	20
	Compressi:	67 byte
	Non compressi:	77 byte

Usare Nomi Alternativi per i Membri di un Archivio

E' facile aggiungere un file ad un archivio usando un nome diverso da quello del file originale, passando il parametro arcname a write().

from zipfile_infolist import print_info
import zipfile

zf = zipfile.ZipFile('zipfile_write_arcname.zip', mode='w')
try:
    zf.write('LEGGIMI.txt', arcname='NON_LEGGIMI.txt')
finally:
    zf.close()
print_info('zipfile_write_arcname.zip')

Non c'è traccia del nome originale del file nell'archivio.

$ python zipfile_write_arcname.py
NON_LEGGIMI.txt
	Commento:
	Modificato:	2010-03-16 21:15:58
	Sistema:	3 (0 = Windows, 3 = Unix)
	versione ZIP:	20
	Compresso:	77 byte
	Non compressi:	77 byte

Scrivere Dati da Sorgenti Diverse Dai File

Talvolta è necessario scrivere in un archivio ZIP, usando dati che non sono provenienti da un file esistente. Invece che scrivere i dati in un file, quindi aggiungere quel file all'archivio ZIP, si può usare il metodo writestr() per aggiungere una stringa di byte ad un archivio direttamente.

from zipfile_infolist import print_info
import zipfile

msg = 'Questi dati non esistevano in un file prima di essere aggiunti al file ZIP'
zf = zipfile.ZipFile('zipfile_writestr.zip',
                     mode='w',
                     compression=zipfile.ZIP_DEFLATED,
                     )
try:
    zf.writestr('da_una_stringa.txt', msg)
finally:
    zf.close()

print_info('zipfile_writestr.zip')

zf = zipfile.ZipFile('zipfile_writestr.zip', 'r')
print zf.read('da_una_stringa.txt')

In questo caso si è usato il parametro compression di ZipFIle per comprimere i dati, visto che writestr() non usa compression come parametro.

$ python zipfile_writestr.py
da_una_stringa.txt
	Commento:
	Modificato:	2010-03-26 20:07:32
	Sistema:	3 (0 = Windows, 3 = Unix)
	versione ZIP:	20
	Compresso:	65 byte
	Non compressi:	74 byte

Questi dati non esistevano in un file prima di essere aggiunti al file ZIP.

Scrivere con una Istanza di ZipInfo

Nella modalità predefinita, la data di modifica viene calcolata quendo si aggiunge un file od una stringa all'archivio. Quando si usa writestr(), è anche possibile passare una istanza di ZipFile per definirla, assieme ad altri meta-dati, attraverso il proprio codice.

import time
import zipfile
from zipfile_infolist import print_info

msg = 'Questi dati non esistevano in un file prima di essere aggiunti al file ZIP'
zf = zipfile.ZipFile('zipfile_writestr_zipinfo.zip',
                     mode='w',
                     )
try:
    info = zipfile.ZipInfo('da_una_stringa.txt',
                           date_time=time.localtime(time.time()),
                           )
    info.compress_type=zipfile.ZIP_DEFLATED
    info.comment='I commenti vanno qui'
    info.create_system=0
    zf.writestr(info, msg)
finally:
    zf.close()

print_info('zipfile_writestr_zipinfo.zip')

In questo esempio, l'ora di modifica è stata impostata all'ora corrente, i dati sono stati compressi, è stato passato un valore False per create_system ed è stato aggiunto un commento.

$ python zipfile_writestr_zipinfo.py
da_una_stringa.txt
	Commento:	I commenti vanno qui
	Modificato:	2010-04-03 10:01:36
	Sistema:	0 (0 = Windows, 3 = Unix)
	versione ZIP:	20
	Compressi:	65 byte
	Non compressi:	74 byte

Accodare ai File

Oltre alla creazione di nuovi archivi, è possibile accodare ad un archivio esistente, oppure aggiungere un archivio alla fine di un file esistente (come ad esempio un file .exe per un archivio auto-estraente). Per aprire un file in accodamento si usa la modalità 'a'

from zipfile_infolist import print_info
import zipfile

print 'creazione archivio'
zf = zipfile.ZipFile('zipfile_append.zip', mode='w')
try:
    zf.write('LEGGIMI.txt')
finally:
    zf.close()

print
print_info('zipfile_append.zip')

print "accoda all'archivio"
zf = zipfile.ZipFile('zipfile_append.zip', mode='a')
try:
    zf.write('LEGGIMI.txt', arcname='LEGGIMI2.txt')
finally:
    zf.close()

print
print_info('zipfile_append.zip')

L'archivio che ne deriva conterrà due membri.

$ python zipfile_append.py
creazione archivio

LEGGIMI.txt
	Commento:
	Modificato:	2010-03-16 21:15:58
            Sistema:	3 (0 = Windows, 3 = Unix)
	versione ZIP:	20
	Compresso:	77 byte
	Non compressi:	77 byte

accoda all'archivio

LEGGIMI.txt
	Commento:
	Modificato:	2010-03-16 21:15:58
	Sistema:	3 (0 = Windows, 3 = Unix)
	versione ZIP:	20
	Compresso:	77 byte
	Non compressi:	77 byte

LEGGIMI2.txt
	Commento:
	Modificato:	2010-03-16 21:15:58
	Sistema:	3 (0 = Windows, 3 = Unix)
	versione ZIP:	20
	Compresso:	77 byte
	Non compressi:	77 byte

Archivi ZIP Python

Dalla versione 2.3 Python ha la capacità di importare moduli contenuti in archivi ZIP, se detti archivi sono compresi in sys.path. La classe PyZipFile può essere usata per costruire un modulo che può essere usato in questo modo. Quando si usa il metodo supplementare writepy(), PyZipFile cerca i file .py in una directory ed aggiunge il corrispondente file .pyo o .pyc all'archivio. Se non esiste alcuno dei due file compilati un file pyc viene creato ed aggiunto.

import sys
import zipfile

if __name__ == '__main__':
    zf = zipfile.PyZipFile('zipfile_pyzipfile.zip', mode='w')
    try:
        zf.debug = 3
        print 'Aggiunge file python'
        zf.writepy('.')
    finally:
        zf.close()
    for name in zf.namelist():
        print name

    print
    sys.path.insert(0, 'zipfile_pyzipfile.zip')
    import zipfile_pyzipfile
    print 'Importato da:', zipfile_pyzipfile.__file__

Quando viene impostato l'attributo di debug di PyZipFile a 3, viene abilitato un debugging dettagliato, in modo da osservare come PyZipFile compili ogni file .py che trova.

$ python zipfile_pyzipfile.py Aggiunge file python
Adding files from directory .
Compiling ./zipfile_write_arcname.py
Adding zipfile_write_arcname.pyc
Compiling ./zipfile_getinfo.py
Adding zipfile_getinfo.pyc
Compiling ./zipfile_read.py
Adding zipfile_read.pyc
Compiling ./zipfile_write_compression.py
Adding zipfile_write_compression.pyc
Compiling ./zipfile_infolist.py
Adding zipfile_infolist.pyc
Compiling ./zipfile_pyzipfile.py
Adding zipfile_pyzipfile.pyc
Compiling ./zipfile_append.py
Adding zipfile_append.pyc
Compiling ./zipfile_write.py
Adding zipfile_write.pyc
Compiling ./zipfile_namelist.py
Adding zipfile_namelist.pyc
Compiling ./zipfile_writestr.py
Adding zipfile_writestr.pyc
Compiling ./zipfile_is_zipfile.py
Adding zipfile_is_zipfile.pyc
zipfile_write_arcname.pyc
zipfile_getinfo.pyc
zipfile_read.pyc
zipfile_write_compression.pyc
zipfile_infolist.pyc
zipfile_pyzipfile.pyc
zipfile_append.pyc
zipfile_write.pyc
zipfile_namelist.pyc
zipfile_writestr.pyc
zipfile_is_zipfile.pyc

Importato da: zipfile_pyzipfile.zip/zipfile_pyzipfile.pyc

Vedere anche:

zipfile
La documentazione della libreria standard per questo modulo.
zlib
La libreria di compressione ZIP.
tarfile
Legge e scrive archivi tar