27

Python の でストリームを圧縮する最良の方法を見つけようとしていますzlib

私は、ファイルのような入力ストリーム (下の ) と、ファイルのような (下の )inputを受け入れる出力関数を持っています。output_function

with open("file") as input:
    output_function(input)

inputそして、チャンクをに送信する前に gzip 圧縮したいと思いますoutput_function:

with open("file") as input:
    output_function(gzip_stream(input))

gzipモジュールは、入力または出力のいずれかがディスク上のgzipされたファイルであると想定しているように見えます。

ただし、ストリーム ファイルのようなものを作成する簡単な方法をネイティブに提供するわけではありません。また、サポートするストリーム圧縮は、手動でデータを圧縮バッファーに追加し、そのバッファーをフラッシュすることによって実現されます。

もちろん、zlib.Compress.compressand zlib.Compress.flush( Compressis returned by zlib.compressobj()) の周りにラッパーを書くこともできますが、バッファ サイズが間違っていたり、似たようなことが起きたりするのではないかと心配です。

では、Python を使用して gzip 圧縮のようなストリーミング ファイルを作成する最も簡単な方法は何でしょうか?

編集:明確にするために、入力ストリームと圧縮された出力ストリームはどちらも大きすぎてメモリに収まらoutput_function(StringIO(zlib.compress(input.read())))ないため、実際には問題を解決できません。

4

6 に答える 6

13

それはかなり厄介です(自己参照など。数分で書くだけで、本当にエレガントなものは何もありません)が、直接gzipではなく使用することに興味がある場合は、必要なことを実行します。zlib

基本的に、GzipWrapは(非常に限定された)ファイルのようなオブジェクトであり、特定の反復可能ファイルからgzip圧縮されたファイルを生成します(たとえば、ファイルのようなオブジェクト、文字列のリスト、任意のジェネレーター...)

もちろん、バイナリを生成するので、「readline」を実装する意味はありませんでした。

他のケースをカバーしたり、反復可能なオブジェクト自体として使用したりするために拡張できるはずです。

from gzip import GzipFile

class GzipWrap(object):
    # input is a filelike object that feeds the input
    def __init__(self, input, filename = None):
        self.input = input
        self.buffer = ''
        self.zipper = GzipFile(filename, mode = 'wb', fileobj = self)

    def read(self, size=-1):
        if (size < 0) or len(self.buffer) < size:
            for s in self.input:
                self.zipper.write(s)
                if size > 0 and len(self.buffer) >= size:
                    self.zipper.flush()
                    break
            else:
                self.zipper.close()
            if size < 0:
                ret = self.buffer
                self.buffer = ''
        else:
            ret, self.buffer = self.buffer[:size], self.buffer[size:]
        return ret

    def flush(self):
        pass

    def write(self, data):
        self.buffer += data

    def close(self):
        self.input.close()
于 2010-02-03T16:29:39.163 に答える
5

gzip モジュールは、ファイルのようなオブジェクトへの圧縮をサポートし、fileobj パラメーターを GzipFile とファイル名に渡します。渡すファイル名は存在している必要はありませんが、gzip ヘッダーには入力が必要なファイル名フィールドがあります。

アップデート

この答えはうまくいきません。例:

# tmp/try-gzip.py 
import sys
import gzip

fd=gzip.GzipFile(fileobj=sys.stdin)
sys.stdout.write(fd.read())

出力:

===> cat .bash_history  | python tmp/try-gzip.py  > tmp/history.gzip
Traceback (most recent call last):
  File "tmp/try-gzip.py", line 7, in <module>
    sys.stdout.write(fd.read())
  File "/usr/lib/python2.7/gzip.py", line 254, in read
    self._read(readsize)
  File "/usr/lib/python2.7/gzip.py", line 288, in _read
    pos = self.fileobj.tell()   # Save current position
IOError: [Errno 29] Illegal seek
于 2010-02-03T14:35:26.713 に答える
2

cStringIO(またはStringIO)モジュールをzlibと組み合わせて使用​​します。

>>> import zlib
>>> from cStringIO import StringIO
>>> s.write(zlib.compress("I'm a lumberjack"))
>>> s.seek(0)
>>> zlib.decompress(s.read())
"I'm a lumberjack"
于 2010-02-03T14:49:08.890 に答える