Scopo | Leggere e scrivere file gzip. |
Versione Python | 1.5.2 e successive |
A partire dal 1 gennaio 2021 le versioni 2.x di Python non sono piu' supportate. Ti invito a consultare la corrispondente versione 3.x dell'articolo per il modulo gzip
Il modulo gzip fornisce una interfaccia tipo file ai file zip GNU. usando zlib per comprimere e decomprimere i dati.
La funzione a livello di modulo
open()
crea una istanza della classe tipo file
GzipFile
. Sono forniti i metodi usuali per scrivere e leggere dati. Per scrivere dati in un file compresso si apre il file in modalità
'w'
.
import gzip
import os
outfilename = 'esempio.txt.gz'
output = gzip.open(outfilename, 'wb')
try:
output.write('Il contenuto del file di esempio va qui.\n')
finally:
output.close()
print outfilename, 'contiene', os.stat(outfilename).st_size, 'byte di dati compressi'
os.system('file -b --mime %s' % outfilename)
$ python gzip_write.py esempio.txt.gz contiene 73 byte di dati compressi application/x-gzip; charset=binary
Si possono usare diversi livelli di compressione passando il parametro compresslevel . I valori validi vanno da 1 a 9 incluso. I valori inferiori sono più veloci e comprimono di meno. I valori più alti sono più lenti e comprimono di più, fino ad un certo punto.
import gzip
import os
import hashlib
def get_hash(data):
return hashlib.md5(data).hexdigest()
data = open('lorem.txt', 'r').read() * 1024
cksum = get_hash(data)
print 'Livello Dimensione Checksum'
print '------- ---------- ---------------------------------'
print 'dati %10d %s' % (len(data), cksum)
for i in xrange(1, 10):
filename = 'livello-di-compressione-%s.gz' % i
output = gzip.open(filename, 'wb', compresslevel=i)
try:
output.write(data)
finally:
output.close()
size = os.stat(filename).st_size
cksum = get_hash(open(filename, 'rb').read())
print '%5d %10d %s' % (i, size, cksum)
La colonna centrale di cifre nel risultato dello script è la dimensione in byte dei file prodotti. Come si vede, per questi dati in input, i valori di compressione più alti non sempre pagano in termini di riduzione di spazio di salvataggio. I risultati possono variare a seconda dai dati in input
$ python gzip_compresslevel.py Livello Dimensione Checksum ------- ---------- --------------------------------- dati 717824 d90f6ff01d9929094f85502aba935250 1 7975 64980dbf11fd43218a926cc9e22947d6 2 7953 bc2543c47a762686ccf947cbe2bd46b2 3 7128 e1ae88a683119ea3a1de79edccdbc835 4 3965 b737ace97be7ca542bf1b2148b872459 5 3965 5d2d77553df74cb3c30849539f01f4d5 6 3965 3a42b581b7ac60baa541119e63ad662e 7 3965 f125c40aa4d945a936cd1f2b31391dc7 8 3965 bd2a44355cfc76c893c4e24e9fc477a7 9 3965 c7d006fc37b1c0466e8e2f794462968a
Una istanza di GzipFile include anche il metodo
writelines()
che può essere usato per scrivere una sequenza di stringhe.
import gzip
import itertools
import os
output = gzip.open('righe_di_esempio.txt.gz', 'wb')
try:
output.writelines(itertools.repeat('La stessa riga, ripetutamente.\n', 10))
finally:
output.close()
os.system('gzcat righe_di_esempio.txt.gz')
$ python gzip_file_writelines.py La stessa riga, ripetutamente. La stessa riga, ripetutamente. La stessa riga, ripetutamente. La stessa riga, ripetutamente. La stessa riga, ripetutamente. La stessa riga, ripetutamente. La stessa riga, ripetutamente. La stessa riga, ripetutamente. La stessa riga, ripetutamente. La stessa riga, ripetutamente.
Per leggere dati da file precedentemente compressi si apre semplicemente il file in modalità
'r'
.
import gzip
input_file = gzip.open('esempio.txt.gz', 'rb')
try:
print input_file.read()
finally:
input_file.close()
Questo esempio legge il file scritto da
gzip_write.py
nella sezione precedente.
$ python gzip_read.py Il contenuto del file di esempio va qui.
Quando si legge un file, è anche possibile cercare e leggere solo alcune parti di dati.
import gzip
input_file = gzip.open('esempio.txt.gz', 'rb')
try:
print 'Intero file:'
all_data = input_file.read()
print all_data
expected = all_data[5:15]
# porta il puntatore ad inizio file
input_file.seek(0)
# si sposta di 5 byte
input_file.seek(5)
print 'A partire da posizione 5 per 10 byte:'
partial = input_file.read(10)
print partial
print
print expected == partial
finally:
input_file.close()
La poszione di
seek()
è relativa ai dati
non compressi
, quindi il chiamante non deve neanche sapere che il file è compresso.
$ python gzip_seek.py Intero file: Il contenuto del file di esempio va qui. A partire da posizione 5 per 10 byte: ntenuto de True
$ python bz2_file_seek.py Intero file: Il contenuto del file di esempio va qui. A partire da posizione 5 per 10 byte: ntenuto de True
E' possibile usare la classe GzipFile per comprimere o decomprimere direttamente un flusso di dati, invece che un intero file. Questo risulta utile quando si lavora con dati che sono trasmessi attraverso un socket o da un handle di file (aperto) già esistente. Si può anche usare un buffer StringIO.
import gzip
from cStringIO import StringIO
import binascii
uncompressed_data = 'La stessa riga, ripetutamente.\n' * 10
print 'NON COMPRESSI:', len(uncompressed_data)
print uncompressed_data
buf = StringIO()
f = gzip.GzipFile(mode='wb', fileobj=buf)
try:
f.write(uncompressed_data)
finally:
f.close()
compressed_data = buf.getvalue()
print 'COMPRESSI:', len(compressed_data)
print binascii.hexlify(compressed_data)
inbuffer = StringIO(compressed_data)
f = gzip.GzipFile(mode='rb', fileobj=inbuffer)
try:
reread_data = f.read(len(uncompressed_data))
finally:
f.close()
print
print 'RILETTURA:', len(reread_data)
print reread_data
$ python gzip_StringIO.py NON COMPRESSI: 310 La stessa riga, ripetutamente. La stessa riga, ripetutamente. La stessa riga, ripetutamente. La stessa riga, ripetutamente. La stessa riga, ripetutamente. La stessa riga, ripetutamente. La stessa riga, ripetutamente. La stessa riga, ripetutamente. La stessa riga, ripetutamente. La stessa riga, ripetutamente. COMPRESSI: 54 1f8b0800be8a9e4b02fff34954282e492d2e4e5428ca4c4fd4019205a925a52589b9a97925a97a5c3ea3d2d8a401eb77dfed36010000 RILETTURA: 310 La stessa riga, ripetutamente. La stessa riga, ripetutamente. La stessa riga, ripetutamente. La stessa riga, ripetutamente. La stessa riga, ripetutamente. La stessa riga, ripetutamente. La stessa riga, ripetutamente. La stessa riga, ripetutamente. La stessa riga, ripetutamente. La stessa riga, ripetutamente.
Vedere anche: