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

Posted

技术标签:

【中文标题】列出 AWS S3 存储桶的特定“文件夹”中的文件【英文标题】:Listing files in a specific "folder" of a AWS S3 bucket 【发布时间】:2016-10-29 08:08:52 【问题描述】:

我需要列出我的 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/&lt;user-id&gt;/

并且我正确地获取了目录中除contacts 子目录之外的所有文件,例如:

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

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

users/&lt;user-id&gt;/contacts/&lt;contact-id&gt;/

但在这种情况下,我也得到了 目录本身作为返回的对象:

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

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

【问题讨论】:

如果您实际上在控制台中创建了“空文件夹”,则会出现这种行为,因为该操作实际上创建了一个带有键 path/to/my/folder/ 的空对象,因此控制台有一个占位符。你在测试时这样做了吗? @Michael-sqlbot 我没有创建任何空文件夹。事实上,所有文件都是由应用程序使用我报告为文件键前缀的文件夹结构上传的。 您可能想在带有斜杠的明显对象上尝试GET,因为如果您没有创建文件夹并且在列出时确实使用了/分隔符withDelimiter("/")对象,这应该意味着您实际上确实有一个以斜杠命名的对象,这可能是由于您的代码中的一个错误以这种方式创建了一个。这样的对象可能在控制台中是不可见的。 这里是代码:codeflex.co/get-list-of-objects-from-s3-directory 确实,Michael 是对的,您的存储桶中有一个具有该键的对象。运行此命令将其删除aws s3api delete-object --bucket X --key path/to/my/folder/。并确保您的代码不会再次创建该对象。 【参考方案1】:

虽然每个人都说 s3 中没有目录和文件,但只有对象(和存储桶),这是绝对正确的,但我建议利用 this 答案中描述的 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(文件),它应该返回(如果前缀正确):users/user-id/contacts/contact-id/file1.txtusers/user-id/contacts/contact-id/file2.txt 对于 commonPrefixes:users/user-id/contacts/contact-id/

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

【讨论】:

ListObjectsV2 仍然没有被突出使用。 .getCommonPrefixes() 真的是去这里的路.. 在这里查看这篇文章,看起来正是你在看的东西:codeflex.co/get-list-of-objects-from-s3-directory 这应该是最好的答案【参考方案2】:

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

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

在上述情况下,对象users/&lt;user-id&gt;/contacts/&lt;contact-id&gt;/ 作为不同的对象存在于 S3 中,但对象 users/&lt;user-id&gt;/ 不存在。这就是你的反应的不同。为什么它们会这样,我们不能告诉你,但在一种情况下有人制造了这个物体,而在另一种情况下却没有。您在 AWS 管理控制台中看不到它,因为控制台将其解释为文件夹并将其隐藏。

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

您的解决方案

由于您是不想要文件夹对象的人,您可以通过检查/ 的最后一个字符来自行排除它。如果是,则忽略响应中的对象。

【讨论】:

我可以得到与 http Post Request 相同的列表吗?【参考方案3】:

您可以检查类型。 s3 有一个特殊的application/x-directory

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

【讨论】:

【参考方案4】:

如果您的目标只是获取文件而不是文件夹,我采用的方法是使用文件 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();

【讨论】:

【参考方案5】:

正如其他人已经说过的,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 文件中。

【讨论】:

【参考方案6】:

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

【讨论】:

我在管理控制台中看不到任何users/&lt;user-id&gt;/contacts/&lt;contact-id&gt;/ 文件。但是,如果它存在,我该如何排除它?【参考方案7】:

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

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

【讨论】:

以上是关于列出 AWS S3 存储桶的特定“文件夹”中的文件的主要内容,如果未能解决你的问题,请参考以下文章

AWS S3仅允许来自存储桶的映像显示在特定IP地址上

AWS S3:更改策略后无法列出存储桶

仅允许从 S3 存储桶的特定文件夹中删除的 IAM 策略

创建单个 IAM 用户以仅访问特定的 S3 存储桶

无需凭据即可从特定 IP 授予对 AWS S3 存储桶的访问权限

AWS:将 IAM 用户限制在 S3 存储桶中的特定文件夹