有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java AWS Lambda:如何在S3存储桶中提取tgz文件并将其放入另一个S3存储桶中

我有一个名为“Source”的S3存储桶。许多'。tgz的文件被实时推送到那个存储桶中。我编写了一个Java代码来提取'。tgz'文件并将其推入“目标”存储桶。我将代码作为Lambda函数推送。我拿到了那本书。tgz'文件作为我的Java代码中的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

共 (3) 个答案

  1. # 1 楼答案

    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)触发一个事件。希望这对你有帮助

  2. # 2 楼答案

    不要使用FileFileOutputStream,使用s3Client.putObject()。要读取tgz文件,可以使用Apache Commons压缩。例如:

    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);
        }
    }
    
  3. # 3 楼答案

    因为其中一个响应是用Python编写的,所以我用这种语言提供了另一种解决方案

    使用/tmp文件系统的解决方案的问题是,AWS只允许在那里(read more)存储512 MB。为了解压或解压更大的文件,最好使用iopackage和BytesIO类,并在内存中处理文件内容。AWS允许为Lambda分配高达3GB的RAM,这大大扩展了最大文件大小。我成功地用1GB S3文件测试了解压

    在我的例子中,将大约2000个文件从1GB tar文件卸载到另一个S3存储桶需要140秒。它可以通过使用多个线程将非tarred文件上传到目标S3 bucket来进一步优化

    下面的示例代码展示了单线程解决方案:

    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)