Bagaimana cara mengompres data zlib di UNIX?

106

Saya telah membuat data yang dikompresi zlib dengan Python, seperti ini:

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

(atau satu-liner shell: echo -n '...' | python2 -c 'import sys,zlib; sys.stdout.write(zlib.compress(sys.stdin.read()))' > /tmp/data)

Sekarang, saya ingin mengompres data dalam shell. Tidak zcatjuga tidak uncompressberfungsi:

$ 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

Tampaknya saya telah membuat file seperti gzip, tetapi tanpa header. Sayangnya saya tidak melihat opsi untuk mengompres data mentah seperti itu di halaman manual gzip, dan paket zlib tidak mengandung utilitas yang dapat dieksekusi.

Apakah ada utilitas untuk mengompresi data zlib mentah?

mykhal
sumber
Ada banyak jawaban tambahan di sini: stackoverflow.com/questions/3178566/deflate-command-line-tool
Jack O'Connor

Jawaban:

140

Dimungkinkan juga untuk mendekompresnya menggunakan + , jika Anda tidak punya, atau ingin menggunakan atau alat lain.
Caranya adalah dengan menambahkan angka ajaib gzip dan metode kompres ke data aktual dari zlib.compress:

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

Suntingan:
@ d0sboots berkomentar: Untuk data RAW Deflate, Anda perlu menambahkan 2 byte null lagi:
"\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x00"

Q on SO ini memberikan informasi lebih lanjut tentang pendekatan ini. Jawaban di sana menunjukkan bahwa ada juga 8 byte footer.

Users @ Vitali-Kushner dan @ mark-bessey melaporkan keberhasilan bahkan dengan file yang terpotong, jadi gzip footer sepertinya tidak diperlukan sepenuhnya.

@ tobias-kienzler menyarankan fungsi ini untuk :
zlipd() (printf "\x1f\x8b\x08\x00\x00\x00\x00\x00" |cat - $@ |gzip -dc)

wkpark
sumber
gzip tidak berfungsi, tetapi zlib-flate tidak (aliran konten halaman pdf).
Daneel S. Yaitskov
69

Pengguna @tino berkomentar di bawah jawaban OpenSSL tapi saya pikir ini harus terpisah:

zlib-flate -uncompress < FILE

Saya mencoba ini dan itu berhasil untuk saya.

zlib-flatedapat ditemukan dalam paket qpdf(di Debian Squeeze dan Fedora 23, sesuai dengan komentar di jawaban lain)

Catskul
sumber
3
Berbeda dengan jawaban yang lain, jawaban ini bekerja pada OS X.
polym
2
@polym, bagaimana Anda zlib-flate menginstal di macOS? Saya tidak melihatnya di mana pun.
Wildcard
4
@Wildcard maaf atas keterlambatan respons. Saya pikir itu datang dengan qpdfpaket yang saya instal dengan yang brewdisebutkan dalam komentar di atas - atau lihat kalimat terakhir dari jawaban ini :). Juga, qpdfsangat keren, jadi lihatlah juga jika Anda punya waktu!
polym
brew instal qpdf, lalu perintah yang tercantum di atas :-) terima kasih!
Fernando Gabrieli
60

Saya telah menemukan solusi (salah satu yang mungkin), menggunakan openssl :

$ openssl zlib -d < /tmp/data

atau

$ openssl zlib -d -in /tmp/data

* CATATAN: fungsionalitas zlib tampaknya tersedia dalam versi openssl terbaru> = 1.0.0 (OpenSSL harus dikonfigurasi / dibangun dengan opsi zlib atau zlib-dinamis, yang terakhir adalah default)

mykhal
sumber
25
Pada Debian Squeeze (yang memiliki OpenSSL 0.9.8) ada zlib-flatedalam qpdfpaket. Dapat digunakan seperti zlib-flate -uncompress < FILE.
Tino
7
zlib dihapus dari versi terbaru OpenSSL sehingga tip ini sangat membantu @Tino
Alexandr Kurilin
1
Terima kasih. Solusi ini memberikan pengalaman yang lebih baik dalam mendekompresi file input pendek daripada jawaban menggunakan "gzip" ("openssl" didekompresi sebanyak mungkin sementara "gzip" membatalkan pencetakan "akhir file yang tak terduga").
Daniel K.
2
@Tino Ini harus menjadi jawaban yang terpisah
Catskul
1
@Tino, ini juga tersedia melalui paket qpdf di Fedora 23. Alexandr Kurilin, zlib masih tersedia di 1.0.2d-fips.
maxschlepzig
28

Saya merekomendasikan pigz dari Mark Adler , rekan penulis perpustakaan kompresi zlib. Jalankan pigzuntuk melihat bendera yang tersedia.

Anda akan melihat:

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

Anda dapat membuka kompresi menggunakan -dflag:

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

Dengan asumsi file bernama 'test':

  • pigz -z test - membuat file terkompresi zlib bernama test.zz
  • pigz -d -z test.zz - Mengonversi test.zz ke file tes yang didekompresi

Pada OSX Anda dapat menjalankan brew install pigz

snodnipper
sumber
7
Bagus temukan! Sepertinya ia dapat mendeteksi file zlib dengan sendirinya, sehingga unpigz test.zzakan berfungsi juga.
Stéphane Chazelas
tidak mendekompresi data saya.
cybernard
1
@cybernard mungkin Anda tidak memiliki file zlib. periksa dengan:$>file hello.txt.zz hello.txt.zz: zlib compressed data
snodnipper
11

zlibmengimplementasikan kompresi yang digunakan oleh gzip, tetapi bukan format file. Sebagai gantinya, Anda harus menggunakan gzipmodul , yang digunakan sendiri zlib.

import gzip
s = '...'
with gzip.open('/tmp/data', 'w') as f:
    f.write(s)
Jeremy Banks
sumber
ok, tapi situasiku adalah bahwa aku punya puluhan / ratusan ribu file yang dibuat, jadi .. :)
1
jadi ... file Anda tidak lengkap. Mungkin Anda harus mengompres mereka dengan zlibdan mengkompres mereka dengan gzip, jika Anda masih belum memiliki data asli.
Greg Hewgill
6
@ mykhal, mengapa Anda membuat sepuluh / ratusan ribu file sebelum memeriksa apakah Anda benar-benar dapat mengompresnya?
3
harpyon, saya dapat mengompres mereka, saya hanya ingin tahu mana yang kurang atau lebih umum pengaturan urg atau dapat digunakan untuk itu, jika saya tidak ingin melakukannya dengan python lagi
3

Ini mungkin melakukannya:

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)

Kemudian jalankan seperti ini:

$ python expander.py data/*
Jeremy Banks
sumber
terima kasih, saya tahu tentang zlib.decompress. mungkin saya akan menggunakan beberapa fungsi berjalan. Saya tidak yakin apakah shell akan menangani sejumlah besar file saya dengan glob wildcard :)
File yang dibuat oleh diperluas masih memeriksa sebagai "data terkompresi zlib" bagi saya, menggunakan fileperintah shell ? Bagaimana itu?
K.-Michael Aye
nggak akan bekerja untukku bahkan dengan header palsu.
cybernard
3

Contoh program yang zpipe.c ditemukan di sini oleh Mark Adler sendiri (dilengkapi dengan distribusi sumber perpustakaan zlib) sangat berguna untuk skenario ini dengan data mentah zlib. Mengkompilasi dengan cc -o zpipe zpipe.c -lzdan untuk dekompresi: zpipe -d < raw.zlib > decompressed. Bisa juga melakukan kompresi tanpa -dflag.

Henno Brandsma
sumber
2

Pada macOS, yang merupakan UNIX compliant penuh UNIX (bersertifikat resmi!), Tidak OpenSSLmemiliki zlibdukungan, tidak ada yang zlib-flatebaik dan sementara solusi pertama bekerja serta semua solusi Python, solusi pertama membutuhkan data ZIP berada dalam file dan semua solusi lain memaksa Anda untuk membuat skrip Python.

Inilah solusi berbasis Perl yang dapat digunakan sebagai command-line one-liner, mendapatkan inputnya melalui pipa STDIN dan yang bekerja di luar kotak dengan macOS yang baru diinstal:

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

Lebih bagus diformat, skrip Perl terlihat seperti ini:

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

Anda dapat menggunakan ini untuk kompres dengan zlib:

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

Dan ini untuk mengempis:

openssl enc -z -none -d < /file/to/deflate
Danny R
sumber
4
Memberikan unknown option '-z'pada Ubuntu 16.04 danOpenSSL 1.0.2g 1 Mar 2016
Tino
2
kesalahan yang sama pada Mac
K.-Michael Aye
-3
zcat -f infile > outfile 

bekerja untuk saya di fedora25

sigxcpu
sumber
1
zcathanya berfungsi dengan file dalam format gzip.
Anthony Geoghegan