Bir gzip akışını zlib ile nasıl açabilirim?


108

Gzip formatındaki dosyalar ( gzipörneğin programla oluşturulmuş ), zlib'in kullandığı ile aynı sıkıştırma algoritması olan "deflate" sıkıştırma algoritmasını kullanır. Ancak, sıkıştırılmış bir gzip dosyasını şişirmek için zlib kullanıldığında, kitaplık bir Z_DATA_ERROR.

Bir gzip dosyasını açmak için zlib'i nasıl kullanabilirim?

Yanıtlar:


118

Diyoruz, zlib ile gzip formatında dosya sıkıştırması için inflateInit2birlikte windowBitsolarak parametresinin 16+MAX_WBITSbu gibi:

inflateInit2(&stream, 16+MAX_WBITS);

Bunu yapmazsanız, zlib kötü bir akış biçiminden şikayet edecektir. Varsayılan olarak, zlib, bir zlib başlığına sahip akışlar oluşturur ve inflate, siz söylemedikçe farklı gzip başlığını tanımaz. Bu, zlib.hbaşlık dosyasının 1.2.1 sürümünden başlayarak belgelenmesine rağmen , zlib kılavuzunda yer almamaktadır . Başlık dosyasından:

windowBitsisteğe bağlı gzip kod çözme için de 15'ten büyük olabilir. windowBitsOtomatik başlık algılama ile zlib ve gzip kod çözmeyi etkinleştirmek için 32 ekleyin veya yalnızca gzip biçiminin kodunu çözmek için 16 ekleyin (zlib biçimi a döndürür Z_DATA_ERROR). Bir gzip akışının kodu strm->adlerçözülüyorsa, adler32 yerine crc32'dir.


35
Python'da:zlib.decompress(data, 15 + 32)
Roman Starkov

3
Teşekkürler, bu yazıyı bulana kadar bu çok sinir bozucuydu.
Alex

Vay canına, bu 2009'un sorusu. Teşekkürler @Greg Hewgill
YuAn Shaolin Maculelê Lai

Belki de gzip akışının yinelemeli açılımı için bazı yönergeler sağlayabilirsiniz. Çıktı akışınızın ve boyutunuzun sabit ve sıkıştırılmış çıktının tamamını depolamak için yeterli olması gereken tek seferlik gzip açmada. Bu değer, veri entropisine göre değişebilen gzip açma etkinliğine bağlıdır. Gerektiğinde çıktı tamponuna dinamik olarak daha fazla alan ayırmanın bir yolu var mı? Teşekkürler
Zohar81

104

piton

zlibkütüphane şunları destekler :

  • RFC 1950 ( zlibsıkıştırılmış biçim)
  • RFC 1951 ( deflatesıkıştırılmış biçim)
  • RFC 1952 ( gzipsıkıştırılmış biçim)

Python zlibmodülü bunları da destekleyecektir.

windowBits seçimi

Ancak zlibtüm bu formatları genişletebilir:

  • deflateformatı (kaldırmak) sıkıştırmak için kullanınwbits = -zlib.MAX_WBITS
  • zlibformatı (kaldırmak) sıkıştırmak için kullanınwbits = zlib.MAX_WBITS
  • gzipformatı (kaldırmak) sıkıştırmak için kullanınwbits = zlib.MAX_WBITS | 16

Http://www.zlib.net/manual.html#Advanced (bölüm inflateInit2) belgelerine bakın

örnekler

test verisi:

>>> deflate_compress = zlib.compressobj(9, zlib.DEFLATED, -zlib.MAX_WBITS)
>>> zlib_compress = zlib.compressobj(9, zlib.DEFLATED, zlib.MAX_WBITS)
>>> gzip_compress = zlib.compressobj(9, zlib.DEFLATED, zlib.MAX_WBITS | 16)
>>> 
>>> text = '''test'''
>>> deflate_data = deflate_compress.compress(text) + deflate_compress.flush()
>>> zlib_data = zlib_compress.compress(text) + zlib_compress.flush()
>>> gzip_data = gzip_compress.compress(text) + gzip_compress.flush()
>>> 

bariz test zlib:

>>> zlib.decompress(zlib_data)
'test'

test için deflate:

>>> zlib.decompress(deflate_data)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
zlib.error: Error -3 while decompressing data: incorrect header check
>>> zlib.decompress(deflate_data, -zlib.MAX_WBITS)
'test'

test için gzip:

>>> zlib.decompress(gzip_data)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
zlib.error: Error -3 while decompressing data: incorrect header check
>>> zlib.decompress(gzip_data, zlib.MAX_WBITS|16)
'test'

veriler ayrıca gzipmodül ile uyumludur :

>>> import gzip
>>> import StringIO
>>> fio = StringIO.StringIO(gzip_data)
>>> f = gzip.GzipFile(fileobj=fio)
>>> f.read()
'test'
>>> f.close()

otomatik başlık algılama (zlib veya gzip)

ilave 32etmek windowBits, tetikleme başlık algılama

>>> zlib.decompress(gzip_data, zlib.MAX_WBITS|32)
'test'
>>> zlib.decompress(zlib_data, zlib.MAX_WBITS|32)
'test'

kullanarak gzipyerine

İçin gzipgzip başlığında kullanabilirsiniz ile veri gzipdoğrudan modül; ama başlık altında lütfen unutmayın , gzipkullanımlarını zlib.

fh = gzip.open('abc.gz', 'rb')
cdata = fh.read()
fh.close()

3
neden bu altın parçası tam olarak bu formattaki belgelerde yok?
Ramon Moraes

lütfen bu yanıtlardan herhangi birini kullanarak cpython'a karşı bir çekme isteği / yama göndermekten çekinmeyin.
dnozay

dizeler için harika cevap, tüm dosyayı belleğe okumadan bir akış için bunu nasıl yapacağınıza dair bir fikriniz var mı?
Josh J

Teşekkür ederim. Cevabınız ile kaynak kodumdaki açma problemimi çözebilirim.
Bethlee

inanılmaz, bu altın bir külçe .. ancak yardım edemem ama bunların 'sihirli sayılar' ile aynı olduğunu hissediyorum? belgelerin neresinde bundan bahsediliyor? baktım, ama gerçekten yeterince sıkı kontrol etmemiş olmalıyım .. ayrıca, tam olarak takip etmediğim notasyonu. | Ne yapar | yani, bu isteğe bağlı mı? ve neden sönük negatif .. MAX_WBITS sabittir .. 🙁
m1nkeh

3

Zlib ve gzip'in yapısı farklıdır. zlib, RFC 1950 kullanır ve gzip, RFC 1952 kullanır , bu nedenle farklı başlıklara sahiptir, ancak geri kalanlar aynı yapıya sahiptir ve RFC 1951'i izler .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.