1. 引言
目前,在使用 AWS 管理控制台时,我们仅能一次下载 AWS S3 存储桶中的一个对象。但是,通过 SDK、CLI 或 CloudShell,我们可以一次下载多个对象。因此,如果需要下载整个 S3 存储桶,这些选项就是我们的选择。
本文将讨论如何使用 AWS 使用整个 S3 存储桶。
2. 使用 aws s3 sync
在我们的虚拟机上安装了 AWS CLI,或者在 CloudShell 中运行时,我们可以通过使用 aws s3 sync
命令复制整个 S3 存储桶:
$ aws s3 sync s3://baeldung-copy-entire-s3 .
download: s3://baeldung-copy-entire-s3/file.txt to ./file.txt
上述命令中,我们将名为 baeldung-copy-entire-s3
的存储桶复制到了当前工作目录。如果我们想要将其复制到不同的目录,只需将 .
替换为目标路径即可。
如果我们的默认区域与存储桶的区域不同,我们需要使用 --region
参数指定存储桶的区域:
$ aws s3 sync s3://baeldung-copy-entire-s3 . --region=eu-west-1
然后,如果我们要排除某个对象或一组对象,则可以将匹配模式传递给 --exclude
选项。--include
选项则相反。
2.1 复制大型存储桶
尽管 S3 对象的最大大小限制为 5TB,但 S3 存储桶没有大小限制。因此,在复制大型 S3 存储桶时,过程可能会很慢。然而,通过使用 aws configure
命令增加 max_concurrent_requests
可以加快速度:
$ aws configure set default.s3.max_concurrent_requests 500
默认情况下,max_concurrent_requests
的值为 10。当我们运行上述命令时,我们可以将其提高到 500。之后,我们将有更多并发下载请求 - 最多可达 500。
当然,除了 max_concurrent_requests
,距离存储桶区域的接近程度以及网络带宽等因素也可能影响速度**。因此,在靠近我们所在区域工作的资源以及选择具有更快吞吐量的资源可以使事情更快。
使用虚拟私有云(VPC)也可以在将存储桶内的内容复制到同一区域的 EC2 实例时使事情更快。S3 转发加速是另一种加快速度的方式,但这将产生额外的成本。此外,其可用性目前有限。
3. 使用 Java SDK
目前,Java SDK 是唯一提供下载 S3 存储桶所有内容方法的 SDK:
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.transfer.s3.S3TransferManager;
import software.amazon.awssdk.transfer.s3.model.DownloadDirectoryRequest;
import java.nio.file.Paths;
public class Bucket {
static final S3TransferManager transferManager = createTM();
// Create Connection
static S3TransferManager createTM() {
S3Client.builder()
.credentialsProvider(DefaultCredentialsProvider.create())
.build();
S3TransferManager transferManager = S3TransferManager.builder()
.build();
return transferManager;
}
static void downloadBucket(S3TransferManager transferManager, String destinationPath, String bucketName) {
transferManager.downloadDirectory(DownloadDirectoryRequest.builder()
.destination(Paths.get(destinationPath))
.bucket(bucketName)
.build())
.completionFuture().join();
}
public static void main(String[] args) {
downloadBucket(transferManager, ".", "baeldung-copy-entire-s3");
}
}
为了使用 Java SDK 复制我们的 S3 存储桶,我们需要以下内容:
DefaultCredentialsProvider
类(software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider
)来为S3Transfermanager
实例提供凭证S3Client
工具(software.amazon.awssdk.services.s3.S3Client
)用于 建立与 AWS S3 的客户端连接S3Transfermanager
工具(software.amazon.awssdk.transfer.s3.S3TransferManager
)DownloadDirectoryRequest
类(software.amazon.awssdk.transfer.s3.model.DownloadDirectoryRequest
)Paths
类(java.nio.file.Paths
)将下载目的地字符串转换为Path
在示例代码中,我们在 Bucket
类中创建了 main
方法之外的两个方法:createTM
和 downloadBucket
。
createTM
方法用于创建与 Amazon S3 的客户端连接。然后,它构建了一个 S3TransferManager
实例并返回。
在 downloadBucket
方法中,downloadDirectory
方法创建了一个 DownloadDirectoryRequest
实例。然后,使用 S3TransferManager
实例,这个实例将存储桶中的所有对象下载到指定的目标位置。
当我们运行代码时,它将整个 S3 存储桶中的文件下载到项目目录的根目录。这是因为我们指定了 destinationPath
为 “.”
。当然,我们可以根据提供的适当字符串指定不同的路径。
在我们的示例中,我们在创建 S3 客户端连接时使用了 DefaultCredentialsProvider
。但我们也可以使用自定义凭证提供程序。
4. 使用 Python SDK
我们可以调整 Python SDK 来执行类似于使用 Java SDK 的操作。让我们尝试使用 Python SDK 下载整个 S3 存储桶:
import boto3
import os
s3 = boto3.client('s3')
bucket = boto3.resource('s3').Bucket('baeldung-copy-entire-s3')
def get_bucket():
for object in bucket.objects.all():
filename = os.getcwd() + '/' + object.key
s3.download_file(bucket.name, object.key, filename)
get_bucket()
在上述示例中,我们基本上遍历了存储桶中的所有对象。然后,我们将每个对象的键作为 key
参数传递给 S3 的 download_file
方法。这样,脚本就可以下载存储桶的所有内容。
我们可以通过调用 list_objects_v2
方法而不是 objects.all()
方法来实现,但无论哪种方式,我们都会使用 for loop
。在这种情况下,如果存储桶包含许多对象,这种方法可能不太高效。当然,在这种情况下,使用 Java SDK 可能会更好。
5. 结论
在本文中,我们讨论了如何使用 AWS CLI、Java SDK 和 Python SDK 下载 S3 存储桶。我们应该记住,当复制大型 S3 存储桶时,Java SDK 方法可能更有效。