Je recherche un wrapper de ligne de commande pour l'algorithme DEFLATE.
J'ai un fichier (git blob) qui est compressé à l'aide de DEFLATE, et je veux le décompresser. La commande gzip ne semble pas avoir une option pour utiliser directement l'algorithme DEFLATE, plutôt que le format gzip.
Idéalement, je recherche un outil Unix/Linux standard qui peut le faire.
edit: Voici la sortie que j'obtiens en essayant d'utiliser gzip pour mon problème:
$ cat .git/objects/c0/fb67ab3fda7909000da003f4b2ce50a53f43e7 | gunzip
gzip: stdin: not in gzip format
MISE À JOUR: Mark Adler a noté que les blobs git ne sont pas des flux DEFLATE bruts, mais des flux zlib. Ceux-ci peuvent être décompressés par l'outil pigz
, qui est pré-emballé dans plusieurs distributions Linux:
$ cat foo.txt
file foo.txt!
$ git ls-files -s foo.txt
100644 7a79fc625cac65001fb127f468847ab93b5f8b19 0 foo.txt
$ pigz -d < .git/objects/7a/79fc625cac65001fb127f468847ab93b5f8b19
blob 14file foo.txt!
Ma réponse originale, conservée pour des raisons historiques:
Si je comprends l'astuce dans le article Wikipedia mentionné par Marc van Kempen, vous pouvez utiliser puff.c
de zlib directement.
Voici un petit exemple:
#include <assert.h>
#include <string.h>
#include "puff.h"
int main( int argc, char **argv ) {
unsigned char dest[ 5 ];
unsigned long destlen = 4;
const unsigned char *source = "\x4B\x2C\x4E\x49\x03\x00";
unsigned long sourcelen = 6;
assert( puff( dest, &destlen, source, &sourcelen ) == 0 );
dest[ 4 ] = '\0';
assert( strcmp( dest, "asdf" ) == 0 );
}
Quelque chose comme ce qui suit imprimera le contenu brut, y compris l'en-tête "$ type $ length\0":
Perl -MCompress::Zlib -e 'undef $/; print uncompress(<>)' \
< .git/objects/27/de0a1dd5a89a94990618632967a1c86a82d577
Vous pouvez le faire avec l'outil de ligne de commande OpenSSL:
openssl zlib -d < $IN > $OUT
Malheureusement, au moins sur Ubuntu, la sous-commande zlib
est désactivée dans la configuration de build par défaut (--no-zlib
--no-zlib-dynamic
), vous devrez donc compiler openssl
à partir de la source pour l'utiliser. Mais il est activé par défaut sur Arch, par exemple.
Edit: Il semble que la commande zlib
ne soit plus prise en charge sur Arch non plus. Cette réponse pourrait ne plus être utile :(
Une doublure en python:
$> python -c "import zlib,sys;print \
repr(zlib.decompress(sys.stdin.read()))" < $IN
Vous pouvez utiliser zlib-flate, comme ceci:
cat .git/objects/c0/fb67ab3fda7909000da003f4b2ce50a53f43e7 \
| zlib-flate -uncompress; echo
Il est là par défaut sur ma machine, mais il fait partie de qpdf - tools for and transforming and inspecting PDF files
si vous devez l'installer.
J'ai sauté un echo
à la fin de la commande, car il est plus facile de lire la sortie de cette façon.
Essayez la commande suivante:
printf "\x1f\x8b\x08\x00\x00\x00\x00\x00" | cat - .git/objects/c0/fb67ab3fda7909000da003f4b2ce50a53f43e7 | gunzip
Aucun outil externe n'est nécessaire.
Source: Comment décompresser les données zlib sous UNIX? sous unix SE
Voici un Ruby one-liner (cd .git/first et identifiez le chemin vers n'importe quel objet):
Ruby -rzlib -e 'print Zlib::Inflate.new.inflate(STDIN.read)' < ./74/c757240ec596063af8cd273ebd9f67073e1208
J'étais fatigué de ne pas avoir de bonne solution pour cela, alors j'ai mis quelque chose sur NPM:
https://github.com/jezell/zlibber
Maintenant, il suffit de diriger la commande pour gonfler/dégonfler.
Voici un exemple d'ouverture d'un objet commit en Python:
$ git show
commit 0972d7651ff85bedf464fba868c2ef434543916a
# all the junk in my commit...
$ python
>>> import zlib
>>> file = open(".git/objects/09/72d7651ff85bedf464fba868c2ef434543916a")
>>> data = file.read()
>>> print data
# binary garbage
>>> unzipped_data = zlib.decompress(data)
>>> print unzipped_data
# all the junk in my commit!
Ce que vous verrez là-bas est presque identique à la sortie de 'git cat-file -p [hash]', sauf que la commande n'imprime pas l'en-tête ('commit' suivi de la taille du contenu et d'un octet nul).
On dirait que Mark Adler nous pense et a écrit un exemple de la façon de le faire avec: http://www.zlib.net/zpipe.c
Il compile avec rien de plus que gcc -lz
et les en-têtes zlib installés. J'ai copié le binaire résultant dans mon /usr/local/bin/zpipe
tout en travaillant avec des trucs git.
les objets git sont compressés par zlib
plutôt que gzip
, donc soit en utilisant zlib
pour le décompresser, soit en utilisant la commande git, c'est-à-dire git cat-file -p <SHA1>
, pour imprimer le contenu.
// save this as deflate.go
package main
import (
"compress/zlib"
"io"
"os"
"flag"
)
var infile = flag.String("f", "", "infile")
func main() {
flag.Parse()
file, _ := os.Open(*infile)
r, err := zlib.NewReader(file)
if err != nil {
panic(err)
}
io.Copy(os.Stdout, r)
r.Close()
}
$ go build deflate.go
$ ./deflate -f .git/objects/c0/fb67ab3fda7909000da003f4b2ce50a53f43e7
Voir http://en.wikipedia.org/wiki/DEFLATE#Encoder_implementations
Il répertorie un certain nombre d'implémentations logicielles, y compris gzip, de sorte que cela devrait fonctionner. Avez-vous essayé d'exécuter gzip sur le fichier? Ne reconnaît-il pas automatiquement le format?
Comment savez-vous qu'il est compressé à l'aide de DEFLATE? Quel outil a été utilisé pour compresser le fichier?
J'ai trouvé cette question à la recherche d'une solution de contournement avec un bogue avec le -text
utilitaire dans la nouvelle version de hadoop dfs
client que je viens d'installer. Le -text
l'utilitaire fonctionne comme cat
, sauf si le fichier en cours de lecture est compressé, il décompresse et affiche le texte brut de manière transparente (d'où le nom).
Les réponses déjà publiées étaient certainement utiles, mais certains d'entre eux ont un problème lorsqu'ils traitent des quantités de données de taille Hadoop - ils lisent tout en mémoire avant de décompresser.
Voici donc mes variations sur les réponses Perl
et Python
ci-dessus qui n'ont pas cette limitation:
Python:
hadoop fs -cat /path/to/example.deflate |
python -c 'import zlib,sys;map(lambda b:sys.stdout.write(zlib.decompress(b)),iter(lambda:sys.stdin.read(4096),""))'
Perl:
hadoop fs -cat /path/to/example.deflate |
Perl -MCompress::Zlib -e 'print uncompress($buf) while sysread(STDIN,$buf,4096)'
Notez l'utilisation du -cat
sous-commande, au lieu de -text
. C'est ainsi que ma solution de contournement ne s'arrête pas après avoir corrigé le bogue. Toutes mes excuses pour la lisibilité de la version python.
les objets git sont des flux zlib (pas de dégonflage brut). pigz décompressera ceux avec le -dz
option.
Pourquoi n'utilisez-vous pas simplement les outils de git pour accéder aux données? Cela devrait être capable de lire n'importe quel objet git:
git show --pretty=raw <object SHA-1>
const zlib = require("zlib");
const adler32 = require("adler32");
const data = "hello world~!";
const chksum = adler32.sum(new Buffer(data)).toString(16);
console.log("789c",zlib.deflateRawSync(data).toString("hex"),chksum);
// or
console.log(zlib.deflateSync(data).toString("hex"));
pigz peut le faire:
apt-get install pigz
unpigz -c .git/objects/c0/fb67ab3fda7909000da003f4b2ce50a53f43e7
Pour compléter la collection, voici des monoplaces Perl pour dégonfler/gonfler/dégonfler brut/gonfler brut.
Dégonfler
Perl -MIO::Compress::Deflate -e 'undef $/; my ($in, $out) = (<>, undef); IO::Compress::Deflate::deflate(\$in, \$out); print $out;'
Gonfler
Perl -MIO::Uncompress::Inflate -e 'undef $/; my ($in, $out) = (<>, undef); IO::Uncompress::Inflate::inflate(\$in, \$out); print $out;'
Dégonflage brut
Perl -MIO::Compress::RawDeflate -e 'undef $/; my ($in, $out) = (<>, undef); IO::Compress::RawDeflate::rawdeflate(\$in, \$out); print $out;'
gonflage brut
Perl -MIO::Uncompress::RawInflate -e 'undef $/; my ($in, $out) = (<>, undef); IO::Uncompress::RawInflate::rawinflate(\$in, \$out); print $out;'