【问题标题】:Handling Streaming TarArchiveEntry to S3 Bucket from a .tar.gz file处理从 .tar.gz 文件流式传输到 S3 存储桶的 TarArchiveEntry
【发布时间】:2018-10-01 23:36:16
【问题描述】:

我正在使用 aws Lamda 解压缩和遍历 tar.gz 文件,然后将它们上传回 s3 压缩保留原始目录结构。

我遇到了通过 PutObjectRequest 将 TarArchiveEntry 流式传输到 S3 存储桶的问题。当第一个条目成功流式传输时,在尝试在 TarArchiveInputStream 上执行 getNextTarEntry() 时,由于底层的 GunzipCompress 充气器为空,而抛出空指针,它在 s3.putObject(new PutObjectRequest(...)) 之前具有适当的值称呼。

我无法找到有关 gz 输入流充气机属性在部分发送到 s3 后如何/为何设置为 null 的文档。 编辑 进一步调查显示,在完成指定内容长度的上传后,AWS 调用似乎正在关闭输入流......无法找到防止这种行为的方法。

下面基本上是我的代码的样子。提前感谢您的帮助、cmets 和建议。

public String handleRequest(S3Event s3Event, Context context) {

    try {
        S3Event.S3EventNotificationRecord s3EventRecord = s3Event.getRecords().get(0);
        String s3Bucket = s3EventRecord.getS3().getBucket().getName();

        // Object key may have spaces or unicode non-ASCII characters.
        String srcKey = s3EventRecord.getS3().getObject().getKey();

        System.out.println("Received valid request from bucket: " + bucketName + " with srckey: " + srcKeyInput);

        String bucketFolder = srcKeyInput.substring(0, srcKeyInput.lastIndexOf('/') + 1);
        System.out.println("File parent directory: " + bucketFolder);

        final AmazonS3 s3Client = AmazonS3ClientBuilder.defaultClient();

        TarArchiveInputStream tarInput = new TarArchiveInputStream(new GzipCompressorInputStream(getObjectContent(s3Client, bucketName, srcKeyInput)));

        TarArchiveEntry currentEntry = tarInput.getNextTarEntry();

        while (currentEntry != null) {
            String fileName = currentEntry.getName();
            System.out.println("For path = " + fileName);

            // checking if looking at a file (vs a directory)
            if (currentEntry.isFile()) {

                System.out.println("Copying " + fileName + " to " + bucketFolder + fileName + " in bucket " + bucketName);
                ObjectMetadata metadata = new ObjectMetadata();
                metadata.setContentLength(currentEntry.getSize());

                s3Client.putObject(new PutObjectRequest(bucketName, bucketFolder + fileName, tarInput, metadata)); // contents are properly and successfully sent to s3
                System.out.println("Done!");
            }

            currentEntry = tarInput.getNextTarEntry(); // NPE here due underlying gz inflator is null;
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        IOUtils.closeQuietly(tarInput);
    }
}

【问题讨论】:

  • 进一步调查显示,在完成指定内容长度的上传后,AWS 调用似乎正在关闭输入流...尚未找到防止这种行为的方法。跨度>
  • getObjectContent()如何生成InputStream

标签: amazon-s3 aws-lambda java-stream tar gunzip


【解决方案1】:

的确如此,AWS 关闭了提供给 PutObjectRequestInputStream,我不知道有什么方法可以指示 AWS 不要这样做。

但是,您可以使用来自Commons IOCloseShieldInputStream 包装TarArchiveInputStream,如下所示:

InputStream shieldedInput = new CloseShieldInputStream(tarInput);

s3Client.putObject(new PutObjectRequest(bucketName, bucketFolder + fileName, shieldedInput, metadata));

当 AWS 关闭提供的 CloseShieldInputStream 时,底层的 TarArchiveInputStream 将保持打开状态。


附言。我不知道ByteArrayInputStream(tarInput.getCurrentEntry()) 做了什么,但它看起来很奇怪。为了这个答案,我忽略了它。

【讨论】:

  • 感谢您抽出宝贵时间和建议!我最终只是扩展了 InputStream 并覆盖了关闭调用。没听说过 CloseShieldInputStream... 也可以试试。
猜你喜欢
  • 1970-01-01
  • 2019-10-14
  • 1970-01-01
  • 2017-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-02
  • 2021-01-09
相关资源
最近更新 更多