2011-10-02 50 views
13

我从S3复制文件到Cloudfiles,我想避免将文件写入磁盘。 Python-Cloudfiles库有一个object.stream()调用,它看起来是我所需要的,但我无法在boto中找到等效的调用。我希望我能像做:如何使用boto将文件从Amazon S3流式传输到Rackspace Cloudfiles?

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

这可能与伯特(或我想任何其他S3库)?

+0

的〔smart_open](https://github.com/piskvorky/smart_open)Python库这样做(阅读和写作)。 – Radim

回答

17

在博托重点对象,它代表在S3对象,可以像使用迭代器,所以你应该能够做这样的事情:

>>> 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 

或者,在你的例子中,你可以这样做:

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

这样一个设计良好的图书馆:) – ehacinom

18

我估计至少一些人看到这个问题会像我,会想办法到流通过线从博托线文件(或逗号逗号,或者任何其他分隔符)。这里有一个简单的方法来做到这一点:

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%为真。希望我仍然可以帮助别人。

+0

拆分其他两种类型的行结束符:'lines = re.split(r'[\ n \ r] +',byte)' - 对于从Excel导出的CSV文件很有帮助 – marcfrodi

+2

one more注意:在f:'循环中的字节完成后,我必须添加'yield unfinished_line',否则最后一行将不会被处理。 – marcfrodi

+1

有没有很好的理由说明为什么这不是Boto3 API的一部分?如果不是,是否应该提交一个拉请求来解决这个问题?我会超级打倒类似的东西! – lol

13

此线程中的其他答案都与boto相关,但S3.Object在boto3中不再可迭代。因此,下面不工作,它产生一个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: 
      file.write(i) 

因此,另一种是使用读法,但这种加载整个S3对象,其中的大文件打交道时内存并不总是一种可能性:

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

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。我很欣赏你揭示了我认为大多数人都在寻找的private __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 
相关问题