2013-04-02 10 views
7

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

botoライブラリでは、読み込むファイルのようなオブジェクトを期待する関数set_contents_from_file()があります。

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

私はこれらの2つの機能を組み合わせたいと思っていますが、1つのAPIはそれ自体で読み込みたい、もう1つのAPIはそれ自身で書きたいと思っています。どちらも受動的な操作(書かれているか、そこから読み込まれているかのような)を知らない。

誰もがこれらをどのように組み合わせて作業するかについてのアイデアはありますか?

編集:私はどこに行くかを暗示していたので、私は1つの答えを受け入れましたが、同じ問題がある場合は、私自身の答え(以下も)が役立ちます。その中の複数の部分のアップロード

答えて

3

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

+0

S3のアップロードが本当に価値の大きさを知っておく必要がありますか?これは、格納中のストリーミング圧縮を実行できないことを意味します。私はこれをチェックするつもりです。 – Alfe

+0

boto-s3-バケットキーに 'set_contents_from_stream()'があります。そのストリーミングについてのヒントは、少なくとも可能であるはずですね、あなたは思いませんか? – Alfe

+0

そのドキュメントから: 'ストリームオブジェクトはシークできず、合計サイズは不明です。 これは、 Content-SizeとContent-MD5をヘッダーに指定できないことを意味します。したがって、 アップロードの場合、MD5計算の遅延は回避されますが、アップロードされた データの完全性を確認できないという不都合があります。 – Alfe

18

私は解決策が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() 
関連する問題