Làm cách nào để giải nén luồng gzip bằng zlib?


108

Các tệp định dạng gzip ( gzipví dụ: được tạo bằng chương trình) sử dụng thuật toán nén "deflate", là thuật toán nén giống như thuật toán zlib sử dụng. Tuy nhiên, khi sử dụng zlib để thổi phồng tệp nén gzip, thư viện sẽ trả về a Z_DATA_ERROR.

Làm cách nào để sử dụng zlib để giải nén tệp gzip?

Câu trả lời:


118

Để giải nén tệp định dạng gzip bằng zlib, hãy gọi inflateInit2với windowBitstham số 16+MAX_WBITSnhư sau:

inflateInit2(&stream, 16+MAX_WBITS);

Nếu bạn không làm điều này, zlib sẽ phàn nàn về định dạng luồng không tốt. Theo mặc định, zlib tạo các luồng với tiêu đề zlib và khi thổi phồng không nhận ra tiêu đề gzip khác trừ khi bạn nói như vậy. Mặc dù điều này được ghi lại bắt đầu từ phiên bản 1.2.1 của zlib.htệp tiêu đề, nhưng nó không có trong hướng dẫn sử dụng zlib . Từ tệp tiêu đề:

windowBitscũng có thể lớn hơn 15 để giải mã gzip tùy chọn. Thêm 32 vào windowBitsđể bật giải mã zlib và gzip với tính năng phát hiện tiêu đề tự động hoặc thêm 16 để chỉ giải mã định dạng gzip (định dạng zlib sẽ trả về a Z_DATA_ERROR). Nếu một luồng gzip đang được giải mã, hãy strm->adlerlà crc32 thay vì adler32.


35
Trong trăn:zlib.decompress(data, 15 + 32)
Roman Starkov

3
Cảm ơn, điều này rất khó chịu cho đến khi tôi tìm thấy bài đăng này.
Alex

Ồ, đây là câu hỏi của năm 2009. Cảm ơn
@Greg

Có lẽ bạn có thể cung cấp một số hướng dẫn về giải nén lặp đi lặp lại của luồng gzip. Trong giải nén gzip một lần, nơi mà luồng đầu ra và kích thước của bạn phải được cố định và đủ để lưu trữ toàn bộ đầu ra đã giải nén. Giá trị này phụ thuộc vào hiệu quả giải nén gzip có thể thay đổi theo entropy dữ liệu. Có cách nào để phân bổ động thêm không gian cho bộ đệm đầu ra khi cần thiết không? Cảm ơn
Zohar81

104

con trăn

zlibthư viện hỗ trợ :

zlibMô-đun python cũng sẽ hỗ trợ những điều này.

chọn windowBits

Nhưng zlibcó thể giải nén tất cả các định dạng đó:

  • để (de-) nén deflateđịnh dạng, sử dụngwbits = -zlib.MAX_WBITS
  • để (de-) nén zlibđịnh dạng, sử dụngwbits = zlib.MAX_WBITS
  • để (de-) nén gzipđịnh dạng, sử dụngwbits = zlib.MAX_WBITS | 16

Xem tài liệu trong http://www.zlib.net/manual.html#Advanced (phần inflateInit2)

ví dụ

dữ liệu thử nghiệm:

>>> 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()
>>> 

kiểm tra rõ ràng cho zlib:

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

kiểm tra 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'

kiểm tra 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'

dữ liệu cũng tương thích với gzipmô-đun:

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

phát hiện tiêu đề tự động (zlib hoặc gzip)

thêm 32vào windowBitssẽ kích hoạt phát hiện tiêu đề

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

sử dụng gzipthay thế

Đối với gzipdữ liệu có tiêu đề gzip, bạn có thể sử dụng gzipmô-đun trực tiếp; nhưng hãy nhớ rằng dưới mui xe , gzipsử dụng zlib.

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

3
tại sao miếng vàng này không có trên tài liệu với định dạng chính xác này?
Ramon Moraes

vui lòng gửi yêu cầu kéo / bản vá chống lại cpython bằng cách sử dụng bất kỳ câu trả lời nào trong số này.
dnozay

câu trả lời tuyệt vời cho chuỗi, bất kỳ ý tưởng nào về cách thực hiện điều này cho một luồng mà không cần đọc toàn bộ tệp vào bộ nhớ?
Josh J

Cảm ơn bạn. Tôi có thể giải quyết vấn đề giải nén trong mã nguồn của mình với câu trả lời của bạn.
Bethlee

Không thể tin được, đây là một viên ngọc vàng .. tuy nhiên tôi không thể không cảm thấy chúng tương đương với 'những con số kỳ diệu'? nơi nào trong tài liệu được đề cập đến? tôi đã nhìn, nhưng phải thực sự đã không kiểm tra đủ kỹ .. ngoài ra, ký hiệu tôi không tuân theo đầy đủ. Cái gì | nghĩa là, đó là tùy chọn? và tại sao giảm phát lại âm .. MAX_WBITS có phải là hằng số không .. 🙁
m1nkeh

3

Cấu trúc của zlib và gzip là khác nhau. zlib sử dụng RFC 1950 và gzip sử dụng RFC 1952 , do đó có các tiêu đề khác nhau nhưng phần còn lại có cấu trúc giống nhau và tuân theo RFC 1951 .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.