¿Cómo descomprimir datos zlib en UNIX?

107

He creado datos comprimidos zlib en Python, así:

import zlib
s = '...'
z = zlib.compress(s)
with open('/tmp/data', 'w') as f:
    f.write(z)

(o de una sola línea en shell: echo -n '...' | python2 -c 'import sys,zlib; sys.stdout.write(zlib.compress(sys.stdin.read()))' > /tmp/data)

Ahora, quiero descomprimir los datos en shell. Ni zcatni uncompresstrabajo:

$ cat /tmp/data | gzip -d -
gzip: stdin: not in gzip format

$ zcat /tmp/data 
gzip: /tmp/data.gz: not in gzip format

$ cat /tmp/data | uncompress -
gzip: stdin: not in gzip format

Parece que he creado un archivo tipo gzip, pero sin encabezados. Desafortunadamente, no veo ninguna opción para descomprimir dichos datos sin procesar en la página de manual de gzip, y el paquete zlib no contiene ninguna utilidad ejecutable.

¿Hay alguna utilidad para descomprimir datos en bruto zlib?

mykhal
fuente
Aquí hay muchas respuestas adicionales: stackoverflow.com/questions/3178566/deflate-command-line-tool
Jack O'Connor

Respuestas:

141

También es posible descomprimirlo usando + estándar , si no tiene, o si desea usar u otras herramientas.
El truco consiste en anteponer el número mágico gzip y el método de compresión a los datos reales de zlib.compress:

printf "\x1f\x8b\x08\x00\x00\x00\x00\x00" |cat - /tmp/data |gzip -dc >/tmp/out

Ediciones:
@ d0sboots comentó: para los datos RAW Deflate, debe agregar 2 bytes nulos más:
"\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x00"

Esta Q sobre SO proporciona más información sobre este enfoque. Una respuesta allí sugiere que también hay un pie de página de 8 bytes.

Los usuarios @ Vitali-Kushner y @ mark-bessey informaron de éxito incluso con archivos truncados, por lo que no parece estrictamente necesario un pie de página de gzip.

@ tobias-kienzler sugirió esta función para el :
zlipd() (printf "\x1f\x8b\x08\x00\x00\x00\x00\x00" |cat - $@ |gzip -dc)

wkpark
fuente
gzip no funciona, pero zlib-flate sí (flujo de contenido de la página pdf).
Daneel S. Yaitskov
70

El usuario @tino comentó a continuación la respuesta de OpenSSL, pero creo que esto debería estar separado:

zlib-flate -uncompress < FILE

Intenté esto y funcionó para mí.

zlib-flatese puede encontrar en el paquete qpdf(en Debian Squeeze y Fedora 23, según los comentarios en otras respuestas)

Catskul
fuente
3
A diferencia de las otras respuestas, esta funciona en OS X.
Polym
2
@polym, ¿cómo te zlib-flate instalaste en macOS? No lo veo en ningún lado.
Comodín el
44
@Wildcard lo siento por la respuesta tardía. Creo que vino con el qpdfpaquete que instalé brewcomo se menciona en el comentario anterior , o mire la última oración de esta respuesta :). Además, qpdfes realmente genial, ¡así que échale un vistazo si tienes tiempo!
polym
brew install qpdf, luego el comando mencionado arriba :-) ¡gracias!
Fernando Gabrieli
60

He encontrado una solución (una de las posibles), está usando openssl :

$ openssl zlib -d < /tmp/data

o

$ openssl zlib -d -in /tmp/data

* NOTA: la funcionalidad zlib aparentemente está disponible en versiones recientes de openssl> = 1.0.0 (OpenSSL tiene que configurarse / construirse con la opción zlib o zlib-dynamic, esta última es la predeterminada)

mykhal
fuente
25
En Debian Squeeze (que tiene OpenSSL 0.9.8) hay zlib-flateen el qpdfpaquete. Se puede usar como zlib-flate -uncompress < FILE.
Tino
77
zlib fue eliminado de las últimas versiones de OpenSSL, por lo que este consejo es muy útil @Tino
Alexandr Kurilin
1
Gracias. Esta solución proporciona una mejor experiencia en descomprimir archivos de entrada cortos que la respuesta usando "gzip" ("openssl" descomprimió tanto como pudo mientras que "gzip" abortó la impresión "final inesperado del archivo").
Daniel K.
2
@Tino, esta debería ser una respuesta separada
Catskul
1
@Tino, también está disponible a través del paquete qpdf en Fedora 23. Alexandr Kurilin, zlib todavía está disponible en 1.0.2d-fips.
maxschlepzig
28

Recomiendo pigz de Mark Adler , coautor de la biblioteca de compresión zlib. Ejecute pigzpara ver las banderas disponibles.

Te darás cuenta:

-z --zlib Compress to zlib (.zz) instead of gzip format.

Puede descomprimir usando la -dbandera:

-d --decompress --uncompress Decompress the compressed input.

Suponiendo un archivo llamado 'prueba':

  • pigz -z test - crea un archivo comprimido zlib llamado test.zz
  • pigz -d -z test.zz - convierte test.zz al archivo de prueba descomprimido

En OSX puedes ejecutar brew install pigz

snodnipper
fuente
77
¡Buen descubrimiento! Parece que puede detectar archivos zlib por sí mismo, por unpigz test.zzlo que funcionará también.
Stéphane Chazelas
No descomprimí mis datos.
cybernard
1
@cybernard tal vez no tienes un archivo zlib. consultar con:$>file hello.txt.zz hello.txt.zz: zlib compressed data
snodnipper
11

zlibimplementa la compresión utilizada por gzip, pero no el formato de archivo. En su lugar, debe usar el gzipmódulo , que también usa zlib.

import gzip
s = '...'
with gzip.open('/tmp/data', 'w') as f:
    f.write(s)
REINSTATE MONICA -Jeremy Banks
fuente
bien, pero mi situación es que tengo decenas / cientos de miles de esos archivos creados, por lo .. :)
1
entonces ... tus archivos están incompletos. Quizás tenga que descomprimirlos zliby recomprimirlos gzipsi aún no tiene los datos originales.
Greg Hewgill
66
@mykhal, ¿por qué creaste diez / cientos de miles de archivos antes de comprobar que realmente podías descomprimirlos?
3
harpyon, puedo descomprimir ellos, me pregunto, que más o menos común urility o ajustes zgip se puede utilizar para que, si yo no quiero hacerlo de nuevo pitón
3

Esto podría hacerlo:

import glob
import zlib
import sys

for filename in sys.argv:
    with open(filename, 'rb') as compressed:
        with open(filename + '-decompressed', 'wb') as expanded:
            data = zlib.decompress(compressed.read())
            expanded.write(data)

Luego ejecútelo así:

$ python expander.py data/*
REINSTATE MONICA -Jeremy Banks
fuente
gracias, lo se zlib.decompress. probablemente usaría alguna función de caminar. No estoy seguro de si Shell manejaría mi gran cantidad de archivos con comodín glob :)
¿El archivo creado por expandido todavía se comprueba como "datos comprimidos zlib" para mí, usando el filecomando de shell ? ¿Como es eso?
K.-Michael Aye
No, no me funciona incluso con el encabezado falso.
cybernard
3

El programa de ejemplo zpipe.c encontrado aquí por el propio Mark Adler (viene con la distribución fuente de la biblioteca zlib) es muy útil para estos escenarios con datos zlib sin procesar. Compilar con cc -o zpipe zpipe.c -lzy para descomprimir: zpipe -d < raw.zlib > decompressed. También puede hacer la compresión sin la -dbandera.

Henno Brandsma
fuente
2

En macOS, que es un UNIX completo compatible con POSIX (¡certificado formalmente!), No OpenSSLtiene zlibsoporte, zlib-flatetampoco lo hay , y aunque la primera solución funciona tan bien como todas las soluciones de Python, la primera solución requiere que los datos ZIP estén en un archivo y todas las demás soluciones te obligan a crear un script de Python.

Aquí hay una solución basada en Perl que se puede usar como línea de comando, obtiene su entrada a través de la tubería STDIN y funciona de forma inmediata con un macOS recién instalado:

cat file.compressed | perl -e 'use Compress::Raw::Zlib;my $d=new Compress::Raw::Zlib::Inflate();my $o;undef $/;$d->inflate(<>,$o);print $o;'

Mejor formateado, el script de Perl se ve así:

use Compress::Raw::Zlib;
my $decompressor = new Compress::Raw::Zlib::Inflate();
my $output;
undef $/;
$decompressor->inflate(<>, $output);
print $output;
Mecki
fuente
1

Puede usar esto para comprimir con zlib:

openssl enc -z -none -e < /file/to/deflate

Y esto para desinflar:

openssl enc -z -none -d < /file/to/deflate
Danny R
fuente
44
Da unknown option '-z'en Ubuntu 16.04 yOpenSSL 1.0.2g 1 Mar 2016
Tino
2
mismo error en Mac
K.-Michael Aye
-3
zcat -f infile > outfile 

funciona para mí en fedora25

sigxcpu
fuente
1
zcatsolo funciona con archivos en formato gzip.
Anthony Geoghegan