Boto3下载gzip并上传为流

时间:2017-03-10 20:08:33

标签: python amazon-s3 lambda boto3

使用python模块boto3,我再说一遍,使用boto3 ,而不是boto。如何从S3下载文件,gzip并重新上传到S3而不将文件写入磁盘?

我正在尝试编写一个AWS lambda函数,将Gzips的所有内容上传到S3。问题是lambda函数限制为512MB的磁盘空间,我的上传可能远远超过这个。

我的假设是可以使用流来做到这一点,任何帮助都将非常感谢!感谢。

[UPDATE]

以下代码有效。它会将块上传到S3,我可以看到生成的*.gz文件。但是gzip标头没有正确添加。打开文件会导致mac Error 32 - Broken Pipe

有趣的是,如果文件大小小于CHUNK_SIZE,即只有一次迭代,则文件被上传,并且没有损坏。

任何看到我做错的事情?

CHUNK_SIZE = 10000000
gz_buffer = io.BytesIO()
gz_stream = gzip.GzipFile(fileobj=gz_buffer, mode='wb', compresslevel=9)
obj = resource.Object(bucket, key)
body = obj.get()['Body']
try:
    while True:
        data = body.read(CHUNK_SIZE)
        if data:
            compressed_bytes = gz_stream.write(data)
            if compressed_bytes < CHUNK_SIZE:
                gz_stream.close()
            cdata = gz_buffer.getvalue()[0:compressed_bytes]
            # Upload cdata as multipart upload
            # This is a little helper function that 
            # uses boto3 create_multipart_upload
            multipart.upload(cdata)
        else:
            # Signal to S3 complete multipart upload
            multipart.complete()
            break
except Exception as e:
    pass

1 个答案:

答案 0 :(得分:1)

我会这样做:

import gzip,io

out_buffer = io.BytesIO()
f = gzip.open(out_buffer,"wb")

obj = resource.Object(bucket, key)
body = obj.get()['Body']
while True:
    read = body.read(500000)
    print('reading...')
    if read:
        # 1.) Stream chunks to gzip
        f.seek(0)
        nb_bytes = f.write(read)
        # 2.) Stream compressed chunks back to S3
        cdata = out_buffer.getvalue()[0:nb_bytes]
        # cdata now holds the compressed chunk of data
    else:
        break
  • 使用io.BytesIO创建&#34;假冒&#34;内存中的文件
  • 在其上映射gzip句柄
  • 循环阅读(您的代码)
  • 在写入之前寻求启动伪文件句柄,因此它不会使用太多内存(当前写入会覆盖先前的迭代写入)
  • 将读取的数据写入gzip句柄,记下写入的字节数(它们根据数据而有所不同,如果它比上一次迭代短,则out_buffer不会缩小我们必须知道长度
  • 使用此长度切片缓冲区的内容以创建压缩块。

请注意,在python 2.x中,您无法将文件对象传递给gzip.open,您必须改为创建Gzip对象,如下所示:

f = gzip.GzipFile("foo.gz","wb",fileobj=out_buffer)