gzip — Leer y escribir archivos GNU zip¶
Propósito: | Lee y escribe archivos zip de GNU. |
---|
El módulo gzip
proporciona una interfaz similar a un archivo para archivos
GNU zip, usando zlib
para comprimir y descomprimir los datos.
Escribir archivos comprimidos¶
La función de nivel de módulo open()
crea una instancia de tipo de archivo
GzipFile
. Se proporcionan los métodos habituales para escribir y leer
bytes.
import gzip
import io
import os
outfilename = 'example.txt.gz'
with gzip.open(outfilename, 'wb') as output:
with io.TextIOWrapper(output, encoding='utf-8') as enc:
enc.write('Contents of the example file go here.\n')
print(outfilename, 'contains', os.stat(outfilename).st_size,
'bytes')
os.system('file -b --mime {}'.format(outfilename))
Para escribir datos en un archivo comprimido, abre el archivo con el modo
'wb'
. Este ejemplo envuelve el GzipFile
con un TextIOWrapper
del
módulo io
para codificar texto Unicode a bytes adecuado para compresión.
$ python3 gzip_write.py
application/x-gzip; charset=binary
example.txt.gz contains 75 bytes
Se pueden utilizar diferentes cantidades de compresión pasando un argumento
compresslevel
. Los valores válidos van de 0 a 9, inclusive. Los valores
más bajos son más rápidos y dan como resultado una menor compresión. Valores
mas altos son más lentos y comprimen más, hasta cierto punto.
import gzip
import io
import os
import hashlib
def get_hash(data):
return hashlib.md5(data).hexdigest()
data = open('lorem.txt', 'r').read() * 1024
cksum = get_hash(data.encode('utf-8'))
print('Level Size Checksum')
print('----- ---------- ---------------------------------')
print('data {:>10} {}'.format(len(data), cksum))
for i in range(0, 10):
filename = 'compress-level-{}.gz'.format(i)
with gzip.open(filename, 'wb', compresslevel=i) as output:
with io.TextIOWrapper(output, encoding='utf-8') as enc:
enc.write(data)
size = os.stat(filename).st_size
cksum = get_hash(open(filename, 'rb').read())
print('{:>5d} {:>10d} {}'.format(i, size, cksum))
La columna central de números en la salida muestra el tamaño en bytes de los archivos producidos comprimiendo la entrada. Para estos datos de entrada, los valores de compresión más altos no necesariamente se pagan en disminución de espacio de almacenamiento. Los resultados variarán, dependiendo de los datos de entrada.
$ python3 gzip_compresslevel.py
Nivel Tamaño Suma de control
----- ---------- ---------------------------------
data 754688 e4c0f9433723971563f08a458715119c
0 754793 ced7189c324eb73a8388492a9024d391
1 9846 5356d357f23e0d5b6d85e920929f0e43
2 8267 8ce46bce238edc095e47e941cebad93d
3 8227 91662517459db94a744671a6b4295b67
4 4167 ad304e3aec585640de9f14306fb32083
5 4167 4381a5d6dff4dd2746387f20411dcfcd
6 4167 ef3a05112ea382abb53bc4a5bee3a52a
7 4167 4723a253d1dc8ddecd4ff7b7adf0bc0b
8 4167 0e1aeba7bdc39f0007039f130d9a28b2
9 4167 eccf47c4c4f1cca3274e57a1b9b9ddd2
Una instancia GzipFile
también incluye un método writelines()
que se
puede utilizar para escribir una secuencia de cadenas.
import gzip
import io
import itertools
import os
with gzip.open('example_lines.txt.gz', 'wb') as output:
with io.TextIOWrapper(output, encoding='utf-8') as enc:
enc.writelines(
itertools.repeat('The same line, over and over.\n',
10)
)
os.system('gzcat example_lines.txt.gz')
Al igual que con un archivo normal, las líneas de entrada deben incluir un carácter de nueva línea.
$ python3 gzip_writelines.py
The same line, over and over.
The same line, over and over.
The same line, over and over.
The same line, over and over.
The same line, over and over.
The same line, over and over.
The same line, over and over.
The same line, over and over.
The same line, over and over.
The same line, over and over.
Leer datos comprimidos¶
Para volver a leer datos de archivos previamente comprimidos, abre el archivo
con modo de lectura binaria ('rb'
) así que no hay traducción de las
terminaciones de línea o decodificación Unicode.
import gzip
import io
with gzip.open('example.txt.gz', 'rb') as input_file:
with io.TextIOWrapper(input_file, encoding='utf-8') as dec:
print(dec.read())
Este ejemplo lee el archivo escrito por gzip_write.py
de la sección
anterior, usar un TextIOWrapper
para decodificar el texto después de que
esta descomprimido.
$ python3 gzip_read.py
Contents of the example file go here.
Al leer un archivo, también es posible buscar y leer solo parte de los datos.
import gzip
with gzip.open('example.txt.gz', 'rb') as input_file:
print('Entire file:')
all_data = input_file.read()
print(all_data)
expected = all_data[5:15]
# rewind to beginning
input_file.seek(0)
# move ahead 5 bytes
input_file.seek(5)
print('Starting at position 5 for 10 bytes:')
partial = input_file.read(10)
print(partial)
print()
print(expected == partial)
La posición seek()
es relativa a los datos sin comprimir, por lo que la
persona que llama no necesita saber que el archivo de datos está comprimido.
$ python3 gzip_seek.py
Entire file:
b'Contents of the example file go here.\n'
Starting at position 5 for 10 bytes:
b'nts of the'
True
Trabajar con Flujos¶
La clase GzipFile
puede usarse para envolver otros tipos de flujos de datos
para que puedan usar la compresión también. Esto es útil cuando los datos se
están transmitiendo a través de un conector o una manejador existente de archivo
(ya abierto). Un buffer BytesIO
también puede ser usado.
import gzip
from io import BytesIO
import binascii
uncompressed_data = b'The same line, over and over.\n' * 10
print('UNCOMPRESSED:', len(uncompressed_data))
print(uncompressed_data)
buf = BytesIO()
with gzip.GzipFile(mode='wb', fileobj=buf) as f:
f.write(uncompressed_data)
compressed_data = buf.getvalue()
print('COMPRESSED:', len(compressed_data))
print(binascii.hexlify(compressed_data))
inbuffer = BytesIO(compressed_data)
with gzip.GzipFile(mode='rb', fileobj=inbuffer) as f:
reread_data = f.read(len(uncompressed_data))
print('\nREREAD:', len(reread_data))
print(reread_data)
Una ventaja de usar GzipFile
en lugar de zlib
es que éste soporta la
interfaz de programación de archivo. Sin embargo, al volver a leer datos
comprimidos con anterioridad, se pasa una longitud explícita a read()
.
Dejando la longitud fuera resultó en un error de CRC, posiblemente porque
BytesIO
devolvió una cadena vacía antes de informar EOF. Al trabajar con
flujos de datos comprimidos, ya sea prefijando los datos con un número entero
que representa la cantidad real de datos para leer o usar la interfaz de
programación de descompresión incremental en zlib
.
$ python3 gzip_BytesIO.py
UNCOMPRESSED: 300
b'The same line, over and over.\nThe same line, over and over.\nT
he same line, over and over.\nThe same line, over and over.\nThe
same line, over and over.\nThe same line, over and over.\nThe sam
e line, over and over.\nThe same line, over and over.\nThe same l
ine, over and over.\nThe same line, over and over.\n'
COMPRESSED: 51
b'1f8b080022caae5a02ff0bc94855284ecc4d55c8c9cc4bd551c82f4b2d5248c
c4b0133f4b8424665916401d3e717802c010000'
REREAD: 300
b'The same line, over and over.\nThe same line, over and over.\nT
he same line, over and over.\nThe same line, over and over.\nThe
same line, over and over.\nThe same line, over and over.\nThe sam
e line, over and over.\nThe same line, over and over.\nThe same l
ine, over and over.\nThe same line, over and over.\n'
Ver también
- Documentación de la biblioteca estándar para gzip
zlib
– El módulozlib
es una interfaz de bajo nivel a la compresión gzip.zipfile
– El módulozipfile
otorga accesso a archivos ZIP.bz2
– El módulobz2
usa el formato de compresión bzip2.tarfile
– El módulotarfile
incluye soporte incorporado para leer archivos tar comprimidos.io
– Bloques de construcción para la creación de flujos de entrada y salida.