簡體   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