16

大きなローカル ファイルがあります。ライブラリを使用して、そのファイルの gzip バージョンを S3 にアップロードしたいと考えていbotoます。ファイルが大きすぎて、アップロード前にディスク上で効率的に gzip できないため、アップロード中にストリーミング方式で gzip する必要があります。

ライブラリは、読み取り元のファイルのようなオブジェクトを期待するboto関数を知っています。set_contents_from_file()

gzipライブラリは、 ; という名前のパラメータを介してオブジェクトを取得できるクラスを認識GzipFileしています。fileobj圧縮時にこのオブジェクトに書き込みます。

これら 2 つの関数を結合したいのですが、一方の API は単独で読み取りを行い、もう一方の API は単独で書き込みを行います。どちらも受動的な操作 (書き込みや読み取りなど) を認識しません。

これらを実用的な方法で組み合わせる方法についてのアイデアはありますか?

編集:どこに行くべきかを示唆していたので、1つの回答(以下を参照)を受け入れましたが、同じ問題がある場合は、マルチパートアップロードを使用したソリューションを実装したため、私自身の回答(以下も)がより役立つかもしれません.

4

3 に答える 3

28

garnaat によって受け入れられた回答のコメントで示唆されたソリューションを実装しました。

import cStringIO
import gzip

def sendFileGz(bucket, key, fileName, suffix='.gz'):
    key += suffix
    mpu = bucket.initiate_multipart_upload(key)
    stream = cStringIO.StringIO()
    compressor = gzip.GzipFile(fileobj=stream, mode='w')

    def uploadPart(partCount=[0]):
        partCount[0] += 1
        stream.seek(0)
        mpu.upload_part_from_file(stream, partCount[0])
        stream.seek(0)
        stream.truncate()

    with file(fileName) as inputFile:
        while True:  # until EOF
            chunk = inputFile.read(8192)
            if not chunk:  # EOF?
                compressor.close()
                uploadPart()
                mpu.complete_upload()
                break
            compressor.write(chunk)
            if stream.tell() > 10<<20:  # min size for multipart upload is 5242880
                uploadPart()

問題なく動作しているようです。結局のところ、ストリーミングはほとんどの場合、データのチャンクにすぎません。この場合、チャンクは約 10MB の大きさですが、誰が気にしますか? 数 GB のチャンクについて話しているのでない限り、これで問題ありません。


Python 3 の更新:

from io import BytesIO
import gzip

def sendFileGz(bucket, key, fileName, suffix='.gz'):
    key += suffix
    mpu = bucket.initiate_multipart_upload(key)
    stream = BytesIO()
    compressor = gzip.GzipFile(fileobj=stream, mode='w')

    def uploadPart(partCount=[0]):
        partCount[0] += 1
        stream.seek(0)
        mpu.upload_part_from_file(stream, partCount[0])
        stream.seek(0)
        stream.truncate()

    with open(fileName, "rb") as inputFile:
        while True:  # until EOF
            chunk = inputFile.read(8192)
            if not chunk:  # EOF?
                compressor.close()
                uploadPart()
                mpu.complete_upload()
                break
            compressor.write(chunk)
            if stream.tell() > 10<<20:  # min size for multipart upload is 5242880
                uploadPart()
于 2013-04-03T23:17:06.487 に答える
6

S3 は真のストリーミング入力 (つまり、チャンク転送エンコーディング) をサポートしていないため、実際にはこれを行う方法はありません。アップロードする前に Content-Length を知る必要があります。それを知る唯一の方法は、最初に gzip 操作を実行することです。

于 2013-04-02T12:14:24.477 に答える