2011-10-02 3 views
13

私はS3からCloudfilesにファイルをコピーしています。ファイルをディスクに書き込まないようにしたいと思います。 Python-Cloudfilesライブラリにはobject.stream()呼び出しがありますが、これは必要なものですが、botoで同等の呼び出しを見つけることはできません。私は、私のような何かを行うことができるだろうことを願っています:botoを使用してAmazon S3からRackspace Cloudfilesにファイルをストリーミングするにはどうすればよいですか?

shutil.copyfileobj(s3Object.stream(),rsObject.stream()) 

は(または私は他のS3ライブラリを想定)のbotoでこれは可能ですか?あなたの例の場合のように、

>>> import boto 
>>> c = boto.connect_s3() 
>>> bucket = c.lookup('garnaat_pub') 
>>> key = bucket.lookup('Scan1.jpg') 
>>> for bytes in key: 
... write bytes to output stream 

または:あなたはこのような何かを行うことができるはずですので

+0

[smart_open](https://github.com/piskvorky/smart_open)Pythonライブラリそれは(読み書きの両方のために)行います。 – Radim

答えて

17

S3でオブジェクトを表してのbotoの主な対象は、イテレータのように使用することができます、あなたができる:

>>> shutil.copyfileobj(key, rsObject.stream()) 
+0

このようにうまく設計されたライブラリ:) – ehacinom

18

を、私はこの質問を見た人のうちの少なくともいくつかは、私のようになり、コンマで行(またはカンマでのbotoラインからファイルをストリームする方法をお勧めします、または任意の把握します他のデリミタ)。これを行う簡単な方法は次のとおりです。

def getS3ResultsAsIterator(self, aws_access_info, key, prefix):   
    s3_conn = S3Connection(**aws_access) 
    bucket_obj = s3_conn.get_bucket(key) 
    # go through the list of files in the key 
    for f in bucket_obj.list(prefix=prefix): 
     unfinished_line = '' 
     for byte in f: 
      byte = unfinished_line + byte 
      #split on whatever, or use a regex with re.split() 
      lines = byte.split('\n') 
      unfinished_line = lines.pop() 
      for line in lines: 
       yield line 

@ garnaatの回答はまだ素晴らしいですし、100%trueです。うまくいけば鉱山はまだ誰かを助ける。

+0

他の両方のタイプの行末で分割: 'lines = re.split(r '[\ n \ r] +'、byte)' - ExcelからエクスポートされたCSVファイルに役立つ – marcfrodi

+2

もう1つ注: 'for byte in f:'ループが完了した後、 'yield unfinished_line'を追加しなければなりませんでした。そうでなければ、最後の行は処理されませんでした。 – marcfrodi

+1

これはBoto3 APIの一部ではない理由がありますか?そうでない場合は、これを修正するプルリクエストを提出する必要がありますか?私はそれのようなものをノックするためにスーパーダウンするだろう! – lol

13

このスレッドのその他の回答はbotoに関連していますが、S3.Objectはboto3でもうiterableではありません。だから、動作しません以下は、それがTypeError: 's3.Object' object is not iterableエラーメッセージ生成します。

s3 = boto3.session.Session(profile_name=my_profile).resource('s3') 
    s3_obj = s3.Object(bucket_name=my_bucket, key=my_key) 

    with io.FileIO('sample.txt', 'w') as file: 
     for i in s3_obj: 
      file.write(i) 

boto3で、オブジェクトの内容がS3.Object.get()['Body']で利用できるいずれかの反復可能ではないので、以下はまだ動作しません。

body = s3_obj.get()['Body'] 
    with io.FileIO('sample.txt', 'w') as file: 
     for i in body.read(): 
      file.write(i) 
body = s3_obj.get()['Body'] 
    with io.FileIO('sample.txt', 'w') as file: 
     for i in body: 
      file.write(i) 

ので、常に可能性がされていない代替は、readメソッドを使用することですが、これは、大きなファイルを扱うメモリ全体S3オブジェクトをロードします

しかし、readメソッドでは、amtパラメータを渡して、元のストリームから読み込みたいバイト数を指定できます。次のように

body = s3_obj.get()['Body'] 
    with io.FileIO('sample.txt', 'w') as file: 
     while file.write(body.read(amt=512)): 
      pass 

一つは、基になるストリームも利用可能であることを認識しbotocore.response.StreamingBodyコードを掘り下げるので、我々は繰り返すことができます::このメソッドは、ストリーム全体が読み込まれるまで、繰り返し呼び出すことができ

body = s3_obj.get()['Body'] 
    with io.FileIO('sample.txt', 'w') as file: 
     for b in body._raw_stream: 
      file.write(b) 

ながら私はまた、使用することができ、いくつかのリンクを見てきましたが、私は試していないグーグル:

+1

非常に便利な答えです。ありがとう@smallo。ほとんどの人が探していると思う私的な__raw_streamを公開していただきありがとうございます。 – saccharine

1

これは、体をストリーミングラッピングの私のソリューションです:

import io 
class S3ObjectInterator(io.RawIOBase): 
    def __init__(self, bucket, key): 
     """Initialize with S3 bucket and key names""" 
     self.s3c = boto3.client('s3') 
     self.obj_stream = self.s3c.get_object(Bucket=bucket, Key=key)['Body'] 

    def read(self, n=-1): 
     """Read from the stream""" 
     return self.obj_stream.read() if n == -1 else self.obj_stream.read(n) 

使用例:

obj_stream = S3ObjectInterator(bucket, key) 
for line in obj_stream: 
    print line 
関連する問題