Список файлов в определенной "папке" ведра AWS 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>/

Почему я получаю такое поведение? Какая разница между двумя запросами на листинг? Мне нужно указать только файлы в каталоге, исключая подкаталоги.

Ответ 1

Все в S3 является объектом. Для вас это могут быть файлы и папки. Но для S3 они просто объекты.

Объекты, которые заканчиваются разделителем (/ в большинстве случаев), обычно воспринимаются как папка, но это не всегда так. Это зависит от приложения. Опять же, в вашем случае вы интерпретируете его как папку. S3 - нет. Это просто еще один объект.

В вашем случае выше users/<user-id>/contacts/<contact-id>/ объектов users/<user-id>/contacts/<contact-id>/ существуют в S3 как отдельный объект, но users/<user-id>/ объекта users/<user-id>/ не работают. Это разница в ваших ответах. Почему они такие, мы не можем вам сказать, но кто-то сделал объект в одном случае, а другой не был. Вы не видите его в консоли управления AWS, потому что консоль интерпретирует его как папку и скрывает его от вас.

Поскольку S3 просто видит эти вещи как объекты, он не "исключает" определенные вещи для вас. Это до клиента, чтобы иметь дело с объектами, как с ними нужно иметь дело.

Ваше решение

Поскольку вы не хотите, чтобы объекты папок, вы можете исключить его самостоятельно, проверив последний символ для /. Если это так, то игнорируйте объект из ответа.

Ответ 2

Хотя все говорят, что в s3 нет каталогов и файлов, но только объекты (и ведра), что абсолютно верно, я бы предложил использовать CommonPrefixes, описанные в этот ответ. Итак, вы можете сделать следующее, чтобы получить список "папок" (commonPrefixes) и "files" (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/file1.txt
  пользователи/идентификатор пользователя/контакты/контакт-ID/file2.txt

для общих префиксов:
пользователи/идентификатор пользователя/контакты/контакт-идентификатор/

Ответ 3

S3 не имеет каталогов, в то время как вы можете перечислить файлы в псевдо-каталоге, как вы продемонстрировали, нет каталога "файл" per-se.
Вы можете непреднамеренно создать файл данных с именем users/<user-id>/contacts/<contact-id>/.

Ответ 4

вы можете проверить тип. s3 имеет специальное приложение /x-каталог

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

Ответ 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.