Contents

用Java在Amazon S3中分段上传

1. 概述

在本教程中,我们将了解如何使用 AWS Java SDK 在 Amazon S3 中处理分段上传。

**简单地说,在分段上传中,我们将内容分成更小的部分并单独上传每个部分。**所有零件在收到时重新组装。 分段上传具有以下优点:

  • 更高的吞吐量——我们可以并行上传部分
  • 更容易的错误恢复——我们只需要重新上传失败的部分
  • 暂停和恢复上传——我们可以在任何时间点上传部分。整个过程可以暂停,剩下的部分可以稍后上传

请注意,将分段上传与 Amazon S3 一起使用时,除最后一部分之外的每个部分的大小必须至少为 5 MB。

2. Maven依赖

在开始之前,我们需要在项目中添加 AWS 开发工具包依赖项:

<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk</artifactId>
    <version>1.11.290</version>
</dependency>

要查看最新版本,请查看Maven Central

3. 执行分段上传

3.1. 创建 Amazon S3 客户端

首先,我们需要**创建一个用于访问 Amazon S3 的客户端。**为此,我们将使用AmazonS3ClientBuilder

AmazonS3 amazonS3 = AmazonS3ClientBuilder
  .standard()
  .withCredentials(new DefaultAWSCredentialsProviderChain())
  .withRegion(Regions.DEFAULT_REGION)
  .build();

这将使用默认凭证提供程序链创建一个客户端来访问 AWS 凭证。

有关默认凭据提供程序链如何工作的更多详细信息,请参阅文档 。如果您使用的区域不是默认区域 ( US West-2 ),请确保将Regions.DEFAULT_REGION替换为该自定义区域。

3.2. 创建 TransferManager 以管理上传

我们将使用TransferManagerBuilder创建一个TransferManager实例。

此类**提供简单的 API 来管理 Amazon S3 的上传和下载,**并管理所有相关任务:

TransferManager tm = TransferManagerBuilder.standard()
  .withS3Client(amazonS3)
  .withMultipartUploadThreshold((long) (5 * 1024 * 1025))
  .build();

分段上传阈值指定大小(以字节为单位),超过该大小应作为分段上传执行。

Amazon S3 规定最小部分大小为 5 MB(对于最后一部分以外的部分),因此我们使用 5 MB 作为分段上传阈值。

3.3. 上传对象

*要使用TransferManager上传对象,我们只需要调用它的*upload()函数。这将并行上传部分:

String bucketName = "blogdemo-bucket";
String keyName = "my-picture.jpg";
String file = new File("documents/my-picture.jpg");
Upload upload = tm.upload(bucketName, keyName, file);

TransferManager.upload()返回一个Upload对象。这可用于检查上传状态和管理上传。我们将在下一节中这样做。

3.4. 等待上传完成

**TransferManager.upload()是一个非阻塞函数;当上传在后台运行时,它会立即返回。

我们可以使用返回的Upload对象等待上传完成后再退出程序:

try {
    upload.waitForCompletion();
} catch (AmazonClientException e) {
    // ...
}

3.5. 跟踪上传进度

跟踪上传进度是很常见的需求;我们可以在ProgressListener实例的帮助下做到这一点:

ProgressListener progressListener = progressEvent -> System.out.println(
  "Transferred bytes: " + progressEvent.getBytesTransferred());
PutObjectRequest request = new PutObjectRequest(
  bucketName, keyName, file);
request.setGeneralProgressListener(progressListener);
Upload upload = tm.upload(request);

我们创建的ProgressListener将继续打印传输的字节数,直到上传完成。

3.6. 控制上传并行度

默认情况下,TransferManager最多使用十个线程来执行分段上传。

但是,我们可以通过在构建TransferManager时指定ExecutorService来控制它:

int maxUploadThreads = 5;
TransferManager tm = TransferManagerBuilder.standard()
  .withS3Client(amazonS3)
  .withMultipartUploadThreshold((long) (5 * 1024 * 1025))
  .withExecutorFactory(() -> Executors.newFixedThreadPool(maxUploadThreads))
  .build();

在这里,我们使用 lambda 来创建ExecutorFactory的包装器实现,并将其传递给*withExecutorFactory()*函数。