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

时间:2016-06-27 10:38:05

标签: java amazon-web-services amazon-s3

我需要列出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>/

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

7 个答案:

答案 0 :(得分:23)

S3中的所有内容都是一个对象。对您而言,它可能是文件和文件夹。但对于S3来说,它们只是对象。

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

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

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

您的解决方案

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

答案 1 :(得分:19)

虽然每个人都说s3中没有目录和文件,但只有对象(和存储桶),这是绝对正确的,我建议利用this回答中描述的CommonPrefixes。 因此,您可以执行以下操作来获取&#34;文件夹列表&#34; (commonPrefixes)和&#34;文件&#34; (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 /

答案 2 :(得分:2)

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

答案 3 :(得分:0)

S3没有目录,而你可以像你演示的那样以伪目录方式列出文件,没有目录&#34; file&#34;每本身。
您可能无意中创建了一个名为users/<user-id>/contacts/<contact-id>/的数据文件。

答案 4 :(得分:0)

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

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

答案 5 :(得分:0)

正如其他人已经说过的那样,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 :(得分:-1)

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

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