如何使用 lambda 和 python 在 s3 上压缩文件

rho*_*erh 5 python amazon-web-services aws-lambda

我需要存档 s3 上存在的多个文件,然后将存档上传回 s3。我正在尝试使用 lambda 和 python。由于某些文件超过 500MB,因此无法在“/tmp”中下载。有什么方法可以将文件一一流式传输并将其存档吗?

小智 7

不写入磁盘,流式传输至 S3 或从 S3 传输

将 Zip 文件从源存储桶流式传输,并使用 Python 将其内容即时读取和写入回另一个 S3 存储桶。

此方法不占用磁盘空间,因此不受大小限制。

基本步骤是:

  • 使用 Boto3 S3 资源对象将 zip 文件从 S3 读取到 BytesIO 缓冲区对象中
  • 使用 zipfile 模块打开对象
  • 使用 namelist 方法迭代 zip 文件中的每个文件
  • 使用资源 meta.client.upload_fileobj 方法将文件写回 S3 中的另一个存储桶

使用 Boto3 的 Python 3.6 代码

s3_resource = boto3.resource('s3')
zip_obj = s3_resource.Object(bucket_name="bucket_name_here", key=zip_key)
buffer = BytesIO(zip_obj.get()["Body"].read())

z = zipfile.ZipFile(buffer)
for filename in z.namelist():
    file_info = z.getinfo(filename)
    s3_resource.meta.client.upload_fileobj(
        z.open(filename),
        Bucket=bucket,
        Key=f'{filename}'
    )
Run Code Online (Sandbox Code Playgroud)

注意:AWS 执行时间限制最长为 15 分钟,因此您可以在这段时间内处理您的巨大文件吗?你只能通过测试才能知道。


小智 6

AWS Lambda 代码:通过存储桶/文件路径中的 ext 从文件创建 zip。


def createZipFileStream(bucketName, bucketFilePath, jobKey, fileExt, createUrl=False):
    response = {} 
    bucket = s3.Bucket(bucketName)
    filesCollection = bucket.objects.filter(Prefix=bucketFilePath).all() 
    archive = BytesIO()

    with zipfile.ZipFile(archive, 'w', zipfile.ZIP_DEFLATED) as zip_archive:
        for file in filesCollection:
            if file.key.endswith('.' + fileExt):   
                with zip_archive.open(file.key, 'w') as file1:
                    file1.write(file.get()['Body'].read())  

    archive.seek(0)
    s3.Object(bucketName, bucketFilePath + '/' + jobKey + '.zip').upload_fileobj(archive)
    archive.close()

    response['fileUrl'] = None

    if createUrl is True:
        s3Client = boto3.client('s3')
        response['fileUrl'] = s3Client.generate_presigned_url('get_object', Params={'Bucket': bucketName,
                                                                                    'Key': '' + bucketFilePath + '/' + jobKey + '.zip'},
                                                              ExpiresIn=3600)

    return response
    
Run Code Online (Sandbox Code Playgroud)

  • 刚刚看到你的回答。我已经以同样的方式实现了它,它非常适合我的情况 (2认同)