【问题标题】:Is there a way to batch upload a collection of InputStreams to Amazon S3 using the Java SDK?有没有办法使用 Java 开发工具包将 InputStreams 集合批量上传到 Amazon S3?
【发布时间】:2021-08-16 15:31:51
【问题描述】:

我知道TransferManager.uploadFileList().uploadFileDirectory() 方法,但是它们接受java.io.File 类型作为参数。我有一组包含 jpeg 图像数据的字节数组输入流。我也不想在上传之前创建内存文件来存储这些数据。

所以我需要的基本上是 S3 客户端的 PutObjectRequest 所做的,但对于 InputStream 对象的集合。此外,如果一次上传失败,我想中止整个事情并且不上传任何内容,就像数据库事务在过程中出现问题时如何撤销更改一样。

Java SDK 可以做到这一点吗?

【问题讨论】:

  • 据我所知,sdk似乎没有提供这样的方法

标签: spring-boot amazon-s3 aws-java-sdk


【解决方案1】:

在我分享答案之前,请考虑升级...

fyi - TransferManagerdeprecated,现在在 JAVA AWS SDK 中支持为 TransferManagerBuilder,如果 TransferManagerBuilder 对象适合您的需求,请考虑升级


现在既然您询问了 TransferManager,您可以 1) 复制下面的代码并将功能/参数替换为您在输入流的内存处理中的自定义并在您的自定义中处理它功能...或; 2) 下面是另一个示例,请尝试按原样使用...


  1. 使用inputstreamissue listed here 修改Github 源代码
private def uploadFile(is: InputStream, s3ObjectName: String, metadata: ObjectMetadata) = {
    try {
      val putObjectRequest = new PutObjectRequest(bucketName, s3ObjectName,
        is, metadata)
      // TransferManager supports asynchronous uploads and downloads
      val upload = transferManager.upload(putObjectRequest)
      upload.addProgressListener(ExceptionReporter.wrap(UploadProgressListener(putObjectRequest)))
    } catch {
      case e: Exception => throw new RuntimeException(e)
    }
  }

  1. 奖金,很好的自定义答案 here 使用 sequence input streams
public void combineFiles() {
    List<String> files = getFiles();
    long totalFileSize = files.stream()
                               .map(this::getContentLength)
                               .reduce(0L, (f, s) -> f + s);

    try {
        try (InputStream partialFile = new SequenceInputStream(getInputStreamEnumeration(files))) {
            ObjectMetadata resultFileMetadata = new ObjectMetadata();
            resultFileMetadata.setContentLength(totalFileSize);
            s3Client.putObject("bucketName", "resultFilePath", partialFile, resultFileMetadata);
        }
    } catch (IOException e) {
        LOG.error("An error occurred while combining files. {}", e);
    }
}

private Enumeration<? extends InputStream> getInputStreamEnumeration(List<String> files) {
    return new Enumeration<InputStream>() {
        private Iterator<String> fileNamesIterator = files.iterator();

        @Override
        public boolean hasMoreElements() {
            return fileNamesIterator.hasNext();
        }

        @Override
        public InputStream nextElement() {
            try {
                return new FileInputStream(Paths.get(fileNamesIterator.next()).toFile());
            } catch (FileNotFoundException e) {
                System.err.println(e.getMessage());
                throw new RuntimeException(e);
            }
        }

    };
}

【讨论】:

  • 感谢您的回答并花时间将其写出来,但这并不是我真正要求的。我有一个 ByteArrayInputStreams 集合,我需要一种更有效的方法来批量上传它们,而无需创建多个 .putObject() 请求。此外,第二个答案也不像我提到的那样相关,我不想在您的代码似乎依赖的上传之前将文件加载到内存中。
  • Afaik 我不认为 SDK 提供了这样做的方法。
猜你喜欢
  • 2015-06-11
  • 2015-08-09
  • 1970-01-01
  • 2023-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-19
  • 2021-07-13
相关资源
最近更新 更多