簡體   English   中英

AWS Lambda:如何提取 S3 存儲桶中的 tgz 文件並將其放入另一個 S3 存儲桶

[英]AWS Lambda: How to extract a tgz file in a S3 bucket and put it in another S3 bucket

我有一個名為“Source”的 S3 存儲桶。 許多“.tgz”文件被實時推送到該存儲桶中。 我編寫了一個 Java 代碼來提取“.tgz”文件並將其推送到“目的地”存儲桶中。 我將代碼推送為 Lambda 函數。 我在我的 Java 代碼中得到了“.tgz”文件作為 InputStream。 如何在 Lambda 中提取它? 我無法在 Lambda 中創建文件,它在 JAVA 中拋出“FileNotFound(Permission Denied)”。

AmazonS3 s3Client = new AmazonS3Client();
S3Object s3Object = s3Client.getObject(new GetObjectRequest(srcBucket, srcKey));
InputStream objectData = s3Object.getObjectContent();
File file = new File(s3Object.getKey());
OutputStream writer = new BufferedOutputStream(new FileOutputStream(file)); <--- It throws FileNotFound(Permission denied) here

由於其中一個響應是在 Python 中,我提供了這種語言的替代解決方案。

使用/tmp文件系統的解決方案的問題是,AWS 只允許在那里存儲512 MB閱讀更多)。 為了解壓或解壓縮較大的文件,最好使用io包和BytesIO類並純粹在內存中處理文件內容。 AWS 允許為 Lambda 分配最多 3GB 的 RAM,這顯着擴展了最大文件大小。 我成功地測試了 1GB S3 文件的解壓。

在我的情況下,將大約 2000 個文件從 1GB tar 文件解壓縮到另一個 S3 存儲桶需要 140 秒。 它可以通過利用多個線程將未壓縮的文件上傳到目標 S3 存儲桶來進一步優化。

下面的示例代碼展示了單線程解決方案:

import boto3
import botocore
import tarfile

from io import BytesIO
s3_client = boto3.client('s3')

def untar_s3_file(event, context):

    bucket = event['Records'][0]['s3']['bucket']['name']
    key = event['Records'][0]['s3']['object']['key']

    input_tar_file = s3_client.get_object(Bucket = bucket, Key = key)
    input_tar_content = input_tar_file['Body'].read()

    with tarfile.open(fileobj = BytesIO(input_tar_content)) as tar:
        for tar_resource in tar:
            if (tar_resource.isfile()):
                inner_file_bytes = tar.extractfile(tar_resource).read()
                s3_client.upload_fileobj(BytesIO(inner_file_bytes), Bucket = bucket, Key = tar_resource.name)
import boto3
import tarfile
from tarfile import TarInfo
import tempfile

s3_client = boto3.client('s3')
s3_resource=boto3.resource('s3')
def lambda_handler(event, context):
    bucket =event['Records'][0]['s3']['bucket']['name']
    key = event['Records'][0]['s3']['object']['key']
    new_bucket='uncompressed-data' #new bucket name
    new_key=key[:-4]
    try:
        with tempfile.SpooledTemporaryFile(mode='w+t') as temp:
            s3_client.download_fileobj(bucket,key, temp)
            temp.seek(0)
            tar=tarfile.open(mode="r:gz", fileobj = temp)
            for TarInfo in tar:
                file_save=tar.extractfile(TarInfo.name)
                s3_client.upload_fileobj(file_save,new_bucket,new_key)
            tar.close()
            temp.close()
    except Exception as e:
        print(e)
        raise e

使用 Python 3.6 並為后綴為“.tgz”的 obejctcreated(all) 觸發事件。 希望這對你有幫助。

不要使用FileFileOutputStream ,使用s3Client.putObject() 要讀取 tgz 文件,您可以使用 Apache Commons Compress。 例子:

ArchiveInputStream tar = new ArchiveInputStreamFactory().
    createArchiveInputStream("tar", new GZIPInputStream(objectData));
ArchiveEntry entry;
while ((entry = tar.getNextEntry()) != null) {
    if (!entry.isDirectory()) {
        byte[] objectBytes = new byte[entry.getSize()];
        tar.read(objectBytes);
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentLength(objectBytes.length);
        metadata.setContentType("application/octet-stream");
        s3Client.putObject(destBucket, entry.getName(), 
            new ByteArrayInputStream(objectBytes), metadata);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM