Tutorial de la biblioteca Python zlib

T

Que es Python zlib

La biblioteca zlib de Python proporciona una interfaz de Python para zlib Biblioteca C, que es una abstracción de nivel superior para la DESINFLAR algoritmo de compresión sin pérdidas. El formato de datos utilizado por la biblioteca se especifica en el RFC 1950 a 1952, que está disponible en http://www.ietf.org/rfc/rfc1950.txt.

El formato de compresión zlib es de uso gratuito y no está cubierto por ninguna patente, por lo que también puede usarlo de manera segura en productos comerciales. Es un formato de compresión sin pérdidas (lo que significa que no pierde ningún dato entre la compresión y la descompresión) y tiene la ventaja de ser portátil en diferentes plataformas. Otro beneficio importante de este mecanismo de compresión es que no expande los datos.

El uso principal de la biblioteca zlib es en aplicaciones que requieren compresión y descompresión de datos arbitrarios, ya sea una cadena, contenido estructurado en memoria o archivos.

Las funcionalidades más importantes incluidas en esta biblioteca son la compresión y la descompresión. La compresión y la descompresión se pueden realizar como operaciones únicas o dividiendo los datos en fragmentos como se vería en un flujo de datos. Ambos modos de funcionamiento se explican en este artículo.

Una de las mejores cosas, en mi opinión, de la biblioteca zlib es que es compatible con gzip formato / herramienta de archivo (que también se basa en DEFLATE), que es una de las aplicaciones de compresión más utilizadas en sistemas Unix.

Compresión

Comprimir una cadena de datos

La biblioteca zlib nos proporciona la compress función, que se puede utilizar para comprimir una cadena de datos. La sintaxis de esta función es muy simple, tomando solo dos argumentos:

compress(data, level=-1)

Aquí el argumento data contiene los bytes que se van a comprimir, y level es un valor entero que puede tomar los valores -1 o 0 a 9. Este parámetro determina el nivel de compresión, donde el nivel 1 es el más rápido y produce el nivel más bajo de compresión. El nivel 9 es el más lento, pero ofrece el nivel más alto de compresión. El valor -1 representa el valor predeterminado, que es el nivel 6. El valor predeterminado tiene un equilibrio entre velocidad y compresión. El nivel 0 no produce compresión.

Un ejemplo de uso del compress El método en una cadena simple se muestra a continuación:

import zlib
import binascii

data="Hello world"

compressed_data = zlib.compress(data, 2)

print('Original data: ' +  data)
print('Compressed data: ' + binascii.hexlify(compressed_data))

Y el resultado es el siguiente:

$ python compress_str.py 
Original data: Hello world
Compressed data: 785ef348cdc9c95728cf2fca49010018ab043d

Figura 1

Si cambiamos el nivel a 0 (sin compresión), la línea 5 se convierte en:

compressed_data = zlib.compress(data, 0)

Y el nuevo resultado es:

$ python compress_str.py 
Original data: Hello world
Compressed data: 7801010b00f4ff48656c6c6f20776f726c6418ab043d

Figura 2

Puede notar algunas diferencias al comparar las salidas al usar 0 o 2 para el nivel de compresión. Usando un nivel de 2 obtenemos una cadena (formateada en hexadecimal) de longitud 38, mientras que con un nivel de 0 obtenemos una cadena hexadecimal con una longitud de 44. Esta diferencia de longitud se debe a la falta de compresión al usar level 0.

Si no formatea la cadena como hexadecimal, como he hecho en este ejemplo, y visualiza los datos de salida, probablemente notará que la cadena de entrada aún se puede leer incluso después de haber sido “comprimida”, aunque tiene algunas formatear caracteres a su alrededor.

Comprimir grandes flujos de datos

Se pueden gestionar grandes flujos de datos con el compressobj() función, que devuelve un objeto de compresión. La sintaxis es la siguiente:

compressobj(level=-1, method=DEFLATED, wbits=15, memLevel=8, strategy=Z_DEFAULT_STRATEGY[, zdict])

La principal diferencia entre los argumentos de esta función y la compress() la función es (aparte de la data parámetro) el wbits argumento, que controla el tamaño de la ventana y si el encabezado y el final se incluyen o no en la salida.

Los posibles valores para wbits son:

Valor Logaritmo del tamaño de la ventana Salida

+9 hasta +15Base 2Incluye encabezado y tráiler de zlib
-9 hasta -15Valor absoluto de wbitsSin encabezado ni tráiler
+25 hasta +31Bajo 4 bits del valorIncluye encabezado gzip y suma de comprobación final

tabla 1

los method El argumento representa el algoritmo de compresión utilizado. Actualmente, el único valor posible es DEFLATED, que es el único método definido en el RFC 1950. El strategy El argumento se relaciona con el ajuste de compresión. A menos que realmente sepa lo que está haciendo, le recomiendo que no lo use y solo use el valor predeterminado.

El siguiente código muestra cómo utilizar el compressobj() función:

import zlib
import binascii

data="Hello world"

compress = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -15)
compressed_data = compress.compress(data)
compressed_data += compress.flush()

print('Original: ' + data)
print('Compressed data: ' + binascii.hexlify(compressed_data))

Después de ejecutar este código, el resultado es:

$ python compress_obj.py 
Original: Hello world
Compressed data: f348cdc9c95728cf2fca490100

figura 3

Como podemos ver en la figura anterior, la frase “Hola mundo” se ha comprimido. Normalmente, este método se utiliza para comprimir flujos de datos que no caben en la memoria a la vez. Aunque este ejemplo no tiene un flujo de datos muy grande, tiene el propósito de mostrar la mecánica de la compressobj() función.

También puede ver cómo sería útil en una aplicación más grande en la que puede configurar la compresión y luego pasar el objeto de compresión a otros métodos / módulos. Esto luego se puede usar para comprimir trozos de datos en serie.

También puede ver cómo sería útil en un escenario en el que tiene un flujo de datos para comprimir. En lugar de tener que acumular todos los datos en la memoria, puede simplemente llamar compress.compress(data) y compress.flush() en su fragmento de datos y luego pasar al siguiente fragmento mientras deja el anterior para que lo limpie la recolección de basura.

Comprimir un archivo

También podemos utilizar el compress() función para comprimir los datos en un archivo. La sintaxis es la misma que en el primer ejemplo.

En el siguiente ejemplo, comprimiremos un archivo de imagen PNG llamado “logo.png” (que, debo señalar, ya es una versión comprimida de la imagen original sin procesar).

El código de ejemplo es el siguiente:

import zlib

original_data = open('logo.png', 'rb').read()
compressed_data = zlib.compress(original_data, zlib.Z_BEST_COMPRESSION)

compress_ratio = (float(len(original_data)) - float(len(compressed_data))) / float(len(original_data))

print('Compressed: %d%%' % (100.0 * compress_ratio))

En el código anterior, el zlib.compress(...) la línea usa la constante Z_BEST_COMPRESSION, que, como su nombre indica, nos da el mejor nivel de compresión que este algoritmo tiene para ofrecer. La siguiente línea calcula el nivel de compresión en función de la relación entre la longitud de los datos comprimidos y la longitud de los datos originales.

El resultado es el siguiente:

$ python compress_file.py 
Compressed: 13%

Figura 4

Como podemos ver, el archivo se comprimió en un 13%.

La única diferencia entre este ejemplo y el primero es la fuente de los datos. Sin embargo, creo que es importante mostrarlo para que pueda tener una idea de qué tipo de datos se pueden comprimir, ya sea solo una cadena ASCII o datos de imagen binaria. Simplemente lea sus datos del archivo como lo haría normalmente y llame al compress método.

Guardar datos comprimidos en un archivo

Los datos comprimidos también se pueden guardar en un archivo para su uso posterior. El siguiente ejemplo muestra cómo guardar texto comprimido en un archivo:

import zlib

my_data="Hello world"

compressed_data = zlib.compress(my_data, 2)

f = open('outfile.txt', 'w')
f.write(compressed_data)
f.close()

El ejemplo anterior comprime nuestra cadena simple “Hola mundo” y guarda los datos comprimidos en un archivo llamado “outfile.txt”. El archivo “outfile.txt”, cuando se abre con nuestro editor de texto, tiene el siguiente aspecto:

Figura 5

Descompresión

Descomprimir una cadena de datos

Una cadena de datos comprimida se puede descomprimir fácilmente utilizando el decompress() función. La sintaxis es la siguiente:

decompress(data, wbits=MAX_WBITS, bufsize=DEF_BUF_SIZE)

Esta función descomprime los bytes en el data argumento. los wbits El argumento se puede utilizar para administrar el tamaño del búfer de historial. El valor predeterminado coincide con el tamaño de ventana más grande. También solicita la inclusión del encabezado y el avance del archivo comprimido. Los posibles valores son:

Valor Logaritmo del tamaño de la ventana Entrada

+8 hasta +15Base 2Incluye encabezado y tráiler de zlib
-8 hasta -15Valor absoluto de wbitsTransmisión sin procesar sin encabezado ni tráiler
+24 a +31 = 16 + (8 a 15)Bajo 4 bits del valorIncluye encabezado gzip y tráiler
+40 a +47 = 32 + (8 a 15)Bajo 4 bits del valorformato zlib o gzip

Tabla 2

El valor inicial del tamaño del búfer se indica en el bufsize argumento. Sin embargo, el aspecto importante de este parámetro es que no necesita ser exacto, porque si se necesita un tamaño de búfer adicional, se aumentará automáticamente.

El siguiente ejemplo muestra cómo descomprimir la cadena de datos comprimidos en nuestro ejemplo anterior:

import zlib

data="Hello world"

compressed_data = zlib.compress(data, 2)
decompressed_data = zlib.decompress(compressed_data)

print('Decompressed data: ' + decompressed_data)

El resultado es el siguiente:

$ python decompress_str.py 
Decompressed data: Hello world

Figura 5

Descomprimir grandes flujos de datos

La descompresión de los flujos de big data puede requerir la administración de la memoria debido al tamaño o la fuente de sus datos. Es posible que no pueda utilizar toda la memoria disponible para esta tarea (o no tenga suficiente memoria), por lo que decompressobj() El método le permite dividir un flujo de datos en varios fragmentos que puede descomprimir por separado.

La sintaxis del decompressobj() la función es la siguiente:

decompressobj(wbits=15[, zdict])

Esta función devuelve un objeto de descompresión, que utiliza para descomprimir los datos individuales. los wbits argumento tiene las mismas características que en decompress() función explicada anteriormente.

El siguiente código muestra cómo descomprimir un gran flujo de datos que se almacena en un archivo. En primer lugar, el programa crea un archivo llamado “outfile.txt”, que contiene los datos comprimidos. Tenga en cuenta que los datos se comprimen utilizando un valor de wbits igual a +15. Esto asegura la creación de un encabezado y un final en los datos.

Luego, el archivo se descomprime utilizando fragmentos de datos. Nuevamente, en este ejemplo, el archivo no contiene una gran cantidad de datos, pero sin embargo, sirve para explicar el concepto de búfer.

El código es el siguiente:

import zlib

data="Hello world"

compress = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, +15)
compressed_data = compress.compress(data)
compressed_data += compress.flush()

print('Original: ' + data)
print('Compressed data: ' + compressed_data)

f = open('compressed.dat', 'w')
f.write(compressed_data)
f.close()

CHUNKSIZE = 1024

data2 = zlib.decompressobj()
my_file = open('compressed.dat', 'rb')            
buf = my_file.read(CHUNKSIZE)

# Decompress stream chunks
while buf:
    decompressed_data = data2.decompress(buf)
    buf = my_file.read(CHUNKSIZE)

decompressed_data += data2.flush()

print('Decompressed data: ' + decompressed_data)

my_file.close()

Después de ejecutar el código anterior, obtenemos los siguientes resultados:

$ python decompress_data.py 
Original: Hello world
Compressed data: x??H???W(?/?I?=
Decompressed data: Hello world

Figura 6

Descomprimir datos de un archivo

Los datos comprimidos contenidos en un archivo se pueden descomprimir fácilmente, como ha visto en ejemplos anteriores. Este ejemplo es muy similar al anterior en el sentido de que estamos descomprimiendo los datos que se originan en un archivo, excepto que en este caso volveremos a usar el único decompress método, que descomprime los datos en una única llamada al método. Esto es útil cuando sus datos son lo suficientemente pequeños como para caber fácilmente en la memoria.

Esto se puede ver en el siguiente ejemplo:

import zlib

compressed_data = open('compressed.dat', 'rb').read()
decompressed_data = zlib.decompress(compressed_data)
print(decompressed_data)

El programa anterior abre el archivo “compressed.dat” creado en un ejemplo anterior, que contiene la cadena comprimida “Hola mundo”.

En este ejemplo, una vez que los datos comprimidos se recuperan y almacenan en la variable compressed_data, el programa descomprime el flujo y muestra el resultado en la pantalla. Como el archivo contiene una pequeña cantidad de datos, el ejemplo usa la decompress() función. Sin embargo, como muestra el ejemplo anterior, también podríamos descomprimir los datos usando el decompressobj() función.

Después de ejecutar el programa obtenemos el siguiente resultado:

$ python decompress_file.py 
Hello world

Figura 7

Terminando

La biblioteca de Python zlib nos proporciona un conjunto útil de funciones para la compresión de archivos usando el formato zlib. Las funciones compress() y decompress() se utilizan normalmente. Sin embargo, cuando hay limitaciones de memoria, las funciones compressobj() y decompressobj() están disponibles para proporcionar más flexibilidad al admitir la compresión / descompresión de flujos de datos. Estas funciones ayudan a dividir los datos en fragmentos más pequeños y manejables, que se pueden comprimir o descomprimir utilizando el compress() y decompress() funciones respectivamente.

Tenga en cuenta que la biblioteca zlib también tiene algunas características más de las que pudimos cubrir en este artículo. Por ejemplo, puede utilizar zlib para calcular la suma de comprobación de algunos datos para verificar su integridad cuando se descomprimen. Para obtener más información sobre funciones adicionales como esta, consulte el documentación oficial.

 

About the author

Ramiro de la Vega

Bienvenido a Pharos.sh

Soy Ramiro de la Vega, Estadounidense con raíces Españolas. Empecé a programar hace casi 20 años cuando era muy jovencito.

Espero que en mi web encuentres la inspiración y ayuda que necesitas para adentrarte en el fantástico mundo de la programación y conseguir tus objetivos por difíciles que sean.

Add comment

Sobre mi

Últimos Post

Etiquetas

Esta web utiliza cookies propias para su correcto funcionamiento. Al hacer clic en el botón Aceptar, aceptas el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad