web-dev-qa-db-ja.com

Python gzipチャンクごとの解凍

メモリとディスクに制限のある環境で、文字列ベースのチャンク(xmlrpcバイナリ転送経由)で送信されたgzipファイルの内容を解凍する必要があります。ただし、zlib.decompress()またはzlib.decompressobj()/ decompress()を使用すると、gzipヘッダー上で両方とも変換されます。 gzipヘッダー(ドキュメント here )を超えてオフセットしようとしましたが、まだbarfを回避できていません。 gzipライブラリ自体は、ファイルからの解凍のみをサポートしているようです。

次のスニペットは、私が何をしたいかを簡単に示しています(実際には、バッファーはローカルファイルから読み取るのではなく、xmlrpcから書き込まれます)。

#! /usr/bin/env python

import zlib

CHUNKSIZE=1000

d = zlib.decompressobj()

f=open('23046-8.txt.gz','rb')
buffer=f.read(CHUNKSIZE)

while buffer:
  outstr = d.decompress(buffer)
  print(outstr)
  buffer=f.read(CHUNKSIZE)

outstr = d.flush()
print(outstr)

f.close()

残念ながら、私が言ったように、このバーフは以下のものを備えています

Traceback (most recent call last):
  File "./test.py", line 13, in <module>
    outstr = d.decompress(buffer)
zlib.error: Error -3 while decompressing: incorrect header check 

理論的には、xmlrpcソースのデータをStringIOにフィードし、それをgzip.GzipFile()のfileobjとして使用できますが、実際には、ファイルの内容全体をメモリに保持するためのメモリがありません。解凍されたデータとして。チャンクごとに処理する必要があります。

フォールバックは、私のxmlrpc-sourcedデータの圧縮をgzipからプレーンzlibに変更することですが、それは他のサブシステムに影響を与えるため、可能であればそれを避けたいと思います。

何か案は?

33
user291294

gzipとzlibはわずかに異なるヘッダーを使用します。

参照 zlibでgzipストリームを解凍するにはどうすればよいですか?

d = zlib.decompressobj(16+zlib.MAX_WBITS)を試してください。

また、チャンクサイズを2の累乗に変更してみてください(CHUNKSIZE=1024)パフォーマンス上の理由から。

41
wisty

私はここでより詳細な答えを持っています: https://stackoverflow.com/a/22310760/1733117

d = zlib.decompressobj(zlib.MAX_WBITS|32)

ドキュメントごとに、ヘッダー(zlibまたはgzip) が自動的に検出されます。

3
dnozay