问题描述
每天在我的 S3 存储桶中生成大约 60 个 CSV 文件。每个文件的平均大小约为 500MB。我想通过 lambda 函数动态压缩所有这些文件(无需在 Lambda 执行中下载文件)并将这些压缩文件上传到另一个 s3 存储桶。我遇到了这些解决方案 1 和 2,但我在实施中仍然遇到问题。现在,我正在尝试将 CSV 文件数据流式传输到一个压缩文件中(这个 zip 文件是在 Lambda tmp 目录中创建的),然后上传到 s3。但是我在写入 zip 文件时收到此错误消息:
[Errno 36] File name too long
这是我的测试 Lambda 函数,我只是尝试使用一个文件,但在实际情况下,我需要单独压缩 50-60 个 CSV 文件:
import boto3
import zipfile
def lambda_handler(event,context):
s3 = boto3.resource('s3')
iterator = s3.Object('bucket-name','file-name').get()['Body'].iter_lines()
my_zip = zipfile.ZipFile('/tmp/test.zip','w')
for line in iterator:
my_zip.write(line)
s3_resource.Meta.client.upload_fileobj(file-name,"another-bucket-name","object-name")
另外,有没有一种方法可以让我从我的 CSV 文件中流式传输数据,将其压缩并将其上传到另一个 s3 存储桶,而无需在 Lambda 内存上实际保存完整的 zip 文件?
解决方法
经过大量研究和试验,我能够让它发挥作用。我为我的问题使用了 smart_open 库,并设法压缩了 550MB 的文件,而我的 Lambda 中仅使用了 150MB 的内存。要使用外部库,我必须在 Lambda 中使用 Layers。这是我的代码:
from smart_open import open,register_compressor
import lzma,os
def lambda_handler(event,context):
with open('s3://bucket-name-where-large-file/file-key-name') as fin:
with open('s3://bucket-name-to-put-zip-file/zip-file-key-name','w') as fout:
for line in fin:
fout.write(line)
请注意,smart_open 支持 .gz
和 .bz2
文件压缩。如果您想以其他格式压缩文件,您可以使用此库的 register_compressor
方法创建您自己的压缩器。