繁体   English   中英

列出 AWS S3 存储桶的特定“文件夹”中的文件

[英]Listing files in a specific “folder” of a AWS S3 bucket

我需要列出 S3 存储桶中某个文件夹中包含的所有文件。

文件夹结构如下

/my-bucket/users/<user-id>/contacts/<contact-id>

我有与用户相关的文件和与某个用户的联系人相关的文件。 我需要列出两者。

要列出我正在使用此代码的文件:

ListObjectsRequest listObjectsRequest = new ListObjectsRequest().withBucketName("my-bucket")
                .withPrefix("some-prefix").withDelimiter("/");
ObjectListing objects = transferManager.getAmazonS3Client().listObjects(listObjectsRequest);

要列出某个用户的文件,我使用了这个前缀:

users/<user-id>/

并且我正确地获取了目录中不包括contacts子目录的所有文件,例如:

users/<user-id>/file1.txt
users/<user-id>/file2.txt
users/<user-id>/file3.txt

要列出某个用户联系人的文件,我使用这个前缀:

users/<user-id>/contacts/<contact-id>/

但在这种情况下,我还将目录本身作为返回对象获取:

users/<user-id>/contacts/<contact-id>/file1.txt
users/<user-id>/contacts/<contact-id>/file2.txt
users/<user-id>/contacts/<contact-id>/

为什么我会出现这种行为? 这两个列表请求之间有什么不同? 我只需要列出目录中的文件,不包括子目录。

虽然每个人都说 s3 中没有目录和文件,只有对象(和存储桶),这是绝对正确的,但我建议利用答案中描述的 CommonPrefixes。 因此,您可以执行以下操作来获取“文件夹”(commonPrefixes)和“文件”(objectSummaries)列表:

ListObjectsV2Request req = new ListObjectsV2Request().withBucketName(bucket.getName()).withPrefix(prefix).withDelimiter(DELIMITER);
ListObjectsV2Result listing = s3Client.listObjectsV2(req);
for (String commonPrefix : listing.getCommonPrefixes()) {
        System.out.println(commonPrefix);
}
for (S3ObjectSummary summary: listing.getObjectSummaries()) {
    System.out.println(summary.getKey());
}

在您的情况下,对于 objectSummaries(文件),它应该返回(如果前缀正确):
用户/用户 ID/联系人/联系人 ID/file1.txt
用户/用户 ID/联系人/联系人 ID/file2.txt

对于 commonPrefixes:
用户/用户 ID/联系人/联系人 ID/

参考: https : //docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html

S3 中的一切都是对象。 对您来说,它可能是文件和文件夹。 但对 S3 来说,它们只是对象。

以分隔符(在大多数情况下为/ )结尾的对象通常被视为文件夹,但并非总是如此。 这取决于应用程序。 同样,在您的情况下,您将其解释为文件夹。 S3 不是。 这只是另一个对象。

在上面的例子中,对象users/<user-id>/contacts/<contact-id>/作为一个不同的对象存在于 S3 中,但对象users/<user-id>/不存在。 这就是你的反应不同。 为什么他们会这样,我们不能告诉你,但有人在一个案例中制造了这个物体,而在另一个案例中却没有。 您在 AWS 管理控制台中看不到它,因为控制台将其解释为文件夹并将其隐藏起来。

由于 S3 只是将这些东西视为对象,因此它不会为您“排除”某些东西。 由客户来处理应该处理的对象。

您的解决方案

既然你不想要的文件夹对象的一个,你可以通过检查的最后一个字符自己排除/ 如果是,则忽略响应中的对象。

你可以检查类型。 s3 有一个特殊的application/x 目录

bucket.objects({:delimiter=>"/", :prefix=>"f1/"}).each { |obj| p obj.object.content_type }

如果您的目标只是获取文件而不是文件夹,那么我采用的方法是使用文件size作为过滤器。 此属性是 AWS 托管的文件的当前大小。 所有文件夹在该属性中都返回 0。 以下是使用 linq 的 C# 代码,但转换为 Java 应该不难。

var amazonClient = new AmazonS3Client(key, secretKey, region);
var listObjectsRequest= new ListObjectsRequest
            {
                BucketName = 'someBucketName',
                Delimiter = 'someDelimiter',
                Prefix = 'somePrefix'
            };
var objects = amazonClient.ListObjects(listObjectsRequest);
var objectsInFolder = objects.S3Objects.Where(file => file.Size > 0).ToList();

正如其他人已经说过的,S3 中的一切都是一个对象。 对您来说,它可能是文件和文件夹。 但对 S3 来说,它们只是对象。

如果您不需要以“/”结尾的对象,您可以安全地删除它们,例如通过 REST api 或 AWS Java SDK(我假设您有写访问权限)。 您不会丢失“嵌套文件”(没有文件,因此您不会丢失名称以您删除的键为前缀的对象)

AmazonS3 amazonS3 = AmazonS3ClientBuilder.standard().withCredentials(new ProfileCredentialsProvider()).withRegion("region").build();
amazonS3.deleteObject(new DeleteObjectRequest("my-bucket", "users/<user-id>/contacts/<contact-id>/"));

请注意,我使用的是ProfileCredentialsProvider因此我的请求不是匿名的。 否则,您将无法删除对象。 我的 AWS 保留密钥存储在 ~/.aws/credentials 文件中。

S3 没有目录,虽然您可以像演示的那样以伪目录方式列出文件,但本身没有目录“文件”。
您可能无意中创建了一个名为users/<user-id>/contacts/<contact-id>/的数据文件。

基于@davioooh 答案。 这段代码对我有用。

ListObjectsRequest listObjectsRequest = new ListObjectsRequest().withBucketName("your-bucket")
            .withPrefix("your/folder/path/").withDelimiter("/");

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM