Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/amazon-s3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何在使用boto上传到s3时使用gzip_Python_Amazon S3_Gzip_Boto_Gzipfile - Fatal编程技术网

Python 如何在使用boto上传到s3时使用gzip

Python 如何在使用boto上传到s3时使用gzip,python,amazon-s3,gzip,boto,gzipfile,Python,Amazon S3,Gzip,Boto,Gzipfile,我有一个很大的本地文件。我想使用boto库将该文件的gzip版本上传到S3中。文件太大,无法在上载之前在磁盘上高效地gzip,因此在上载过程中应以流式方式gzip boto库知道一个函数set\u contents\u from\u file(),该函数需要一个类似文件的对象来读取 gzip库知道类GzipFile,该类可以通过名为fileobj的参数获取对象;压缩时,它将写入此对象 我想将这两个函数结合起来,但是一个API想要自己读,另一个API想要自己写;两者都不知道被动操作(如写入或读取)

我有一个很大的本地文件。我想使用
boto
库将该文件的gzip版本上传到S3中。文件太大,无法在上载之前在磁盘上高效地gzip,因此在上载过程中应以流式方式gzip

boto
库知道一个函数
set\u contents\u from\u file()
,该函数需要一个类似文件的对象来读取

gzip
库知道类
GzipFile
,该类可以通过名为
fileobj
的参数获取对象;压缩时,它将写入此对象

我想将这两个函数结合起来,但是一个API想要自己读,另一个API想要自己写;两者都不知道被动操作(如写入或读取)

有没有人对如何以一种工作方式将这些结合起来有想法


编辑:我接受了一个答案(见下文),因为它暗示了我该去哪里,但如果你有同样的问题,你可能会发现我自己的答案(也在下文)更有用,因为我在其中实现了一个使用多部分上传的解决方案。

真的没有办法做到这一点,因为S3不支持真正的流式输入(即分块传输编码)。在上传之前,您必须知道内容长度,唯一知道的方法是先执行gzip操作。

我实施了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()
导入cStringIO
导入gzip
def sendFileGz(bucket、key、fileName、后缀='.gz'):
键+=后缀
mpu=bucket.initiate\u multipart\u upload(密钥)
stream=cStringIO.StringIO()
compressor=gzip.gzip文件(fileobj=stream,mode='w')
def uploadPart(partCount=[0]):
零件计数[0]+=1
stream.seek(0)
mpu.upload\u part\u from\u文件(流,partCount[0])
stream.seek(0)
stream.truncate()
将文件(文件名)作为输入文件:
虽然为True:#直到EOF
chunk=inputFile.read(8192)
如果不是块:#EOF?
压缩机关闭()
上传部分()
mpu.complete_upload()
打破
compressor.write(块)

如果stream.tell()>10您还可以使用gzip轻松压缩字节,并按如下方式轻松上传:

import gzip
import boto3

cred = boto3.Session().get_credentials()

s3client = boto3.client('s3',
                            aws_access_key_id=cred.access_key,
                            aws_secret_access_key=cred.secret_key,
                            aws_session_token=cred.token
                            )

bucketname = 'my-bucket-name'      
key = 'filename.gz'  

s_in = b"Lots of content here"
gzip_object = gzip.compress(s_in)

s3client.put_object(Bucket=bucket, Body=gzip_object, Key=key)
可以将
中的
s_替换为任何字节、io.BytesIO、pickle转储、文件等


如果你想上传压缩的Json,那么这里有一个很好的例子:

S3上传真的需要知道值的大小吗?这确实意味着在存储时不能执行流式压缩。我将对此进行检查。这里有一个
set\u contents\u from\u stream()
在boto-s3-bucket-keys中。这至少暗示了流媒体应该是可能的,你不认为吗?从它的文档中:
流对象不可查找,总大小未知。这意味着我们不能在标题中指定内容大小和Content-MD5。因此对于大量上传,计算延迟避免了使用MD5,但会受到无法验证上传数据完整性的惩罚。
仅在Google云存储上支持
从流中设置内容
方法,而不支持S3。是的,S3支持多部分上传。但是,上传前必须知道每个部分。S中不支持流式上传3.将您的巨大文件分解为多个部分并使用多部分听起来是一种合理的方法。mpu是如何定义的?
s3.Bucket(“”).Object(“”)与
boto3.client('s3')
我们使用的
s3.create_multipart_upload(Bucket=dst_Bucket,Key=dst_Key)
session=boto3.session.session();s3=session.resource('s3');bucket=s3.bucket(bucket_name);mpu=bucket.initiate_multipart_upload(key);
我更改了
stream.tell()>10有趣的效果。但我看不到与更改有任何联系。在您调查之后,让我们听听这是什么原因。10create_multipart_upload()只接受关键字参数。看起来这是试图在内存中处理整个内容,对吗?考虑一下我想上传的10GB日志文件。这是可行的吗?@ alftrue,文件应该适合内存中的这种方法。但是,它更容易解决问题的标题。“如何在使用boto上传到s3时进行gzip”。不,因为严格来说,您在上传时不进行gzip,但在之前(内存中)。在我的用例中,我有一个非常大的文件(10GB或类似文件)并且想在S3中存储gzip版本的文件。唯一直接的方法是在上传文件之前gzip文件,但这意味着需要提供额外的存储或运行时内存;同时在上传时进行压缩似乎是可行的,因为它同时做两件事。我的问题正是针对这一点是应该是新接受的答案。@Alfe的答案不再是现成的——至少在我尝试的时候不是。多个issues@JoshWolff这不可能,因为它没有回答包含以下方面的问题:»文件太大,无法在上载之前在磁盘上高效地gzip它。«这里的回答回答了一个不同的问题uestion(没有提到的限制)。但是感谢您指出我以前的解决方案存在问题。我不再使用它了,所以我不知道。您可能应该在其他答案的评论中报告您的发现,以便其他人可以从您的工作中受益。
import gzip
import boto3

cred = boto3.Session().get_credentials()

s3client = boto3.client('s3',
                            aws_access_key_id=cred.access_key,
                            aws_secret_access_key=cred.secret_key,
                            aws_session_token=cred.token
                            )

bucketname = 'my-bucket-name'      
key = 'filename.gz'  

s_in = b"Lots of content here"
gzip_object = gzip.compress(s_in)

s3client.put_object(Bucket=bucket, Body=gzip_object, Key=key)