Amazon S3 Client НЕ перечисляет все папки в корзине - PullRequest
0 голосов
/ 27 августа 2018

Я пытаюсь перечислить все так называемые folders и sub-folders в поле s3.Теперь, когда я пытаюсь рекурсивно перечислить все папки в пути, я не использую функцию withDelimeter().Все так называемые folder имена должны заканчиваться /, и это моя логика, чтобы перечислить все папки и подпапки.

Вот код scala (Намеренно не вставлять catchкод здесь):

val awsCredentials = new BasicAWSCredentials(awsKey, awsSecretKey)
val client = new AmazonS3Client(awsCredentials)
def listFoldersRecursively(bucketName: String, fullPath: String): List[String] = {
  try {
    val objects = client.listObjects(bucketName).getObjectSummaries
    val listObjectsRequest = new ListObjectsRequest()
      .withPrefix(fullPath)
      .withBucketName(bucketName)
    val folderPaths = client
      .listObjects(listObjectsRequest)
      .getObjectSummaries()
      .map(_.getKey)
    folderPaths.filter(_.endsWith("/")).toList
  }
}

Вот структура моего bucket через s3 client

Вот список, который я получаю, используя это scala код

Без какого-либо видимого шаблона многие папки отсутствуют в списке найденных папок.Я не использовал

client.listObjects(listObjectsRequest).getCommonPrefixes.toList

, потому что по какой-то причине он возвращал пустой список.

PS: не удалось добавить фотографии в сообщение напрямую из-за того, что он новый пользователь.

Ответы [ 3 ]

0 голосов
/ 27 августа 2018

Без какого-либо видимого шаблона многие папки отсутствуют в списке найденных папок.

Вот ваша проблема: вы предполагаете, что всегда должны быть объекты склавиши, оканчивающиеся на / для обозначения папок.

Это неверное предположение.Они будут там только в том случае, если вы их создали, либо через консоль S3, либо через API.Нет никаких оснований ожидать их, поскольку S3 на самом деле не нуждается в них и не использует их ни для чего, а служба S3 сама не создает их самопроизвольно.

Если вы используете API для загрузки объекта с ключомfoo/bar.txt, это не создает папку foo/ как отдельный объект.Для удобства он будет отображаться как папка на консоли, но его там нет, если только в какой-то момент вы его не умышленно создали.

Конечно, единственный способ загрузить такой объект с консоли - это "создать "папку, если она уже не появляется - но появляется в консоли не обязательно соответствует существует как отдельный объект.

Фильтрация на endsWith("/") isневерная логика.

Именно поэтому базовый API включает CommonPrefixes в каждый ответ ListObjects, если указаны delimiter и prefix.Это список следующего уровня «папок», в который вы должны рекурсивно углубиться, чтобы найти следующий уровень.

Если вы укажете префикс, все ключи, содержащие одинаковыеСтрока между префиксом и первым появлением разделителя после префикса сгруппирована в один элемент результата, называемый CommonPrefixes.Если вы не укажете параметр префикса, подстрока начинается с начала ключа.Ключи, сгруппированные в элементе результата CommonPrefixes, не возвращаются в другом месте в ответе.

https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketGET.html

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

0 голосов
/ 03 сентября 2018

Что ж, на случай, если кто-то столкнется с той же проблемой в будущем, я использовал альтернативную логику, предложенную @Michael выше, я перебрал все ключи, выделив их при последнем появлении /. Первым index из возвращенного списка + / был ключ папки, добавленный в другой список. В конце вернул список unique, в который я добавлял. Это дало мне все folders и sub-folders в определенном месте префикса.

Обратите внимание, что я не использовал CommonPrefixes, потому что я не использовал delimiter, и это потому, что я не хотел список folders на определенном уровне, а вместо этого recursively get все folders и sub-folders

def listFoldersRecursively(bucketName: String, fullPath: String): List[String] = {
    try {
      val objects = client.listObjects(bucketName).getObjectSummaries
      val listObjectsRequest = new ListObjectsRequest()
        .withPrefix(fullPath)
        .withBucketName(bucketName)

      val folderPaths = client.listObjects(listObjectsRequest)
        .getObjectSummaries()
        .map(_.getKey)
        .toList

      val foldersList: ArrayBuffer[String] = ArrayBuffer()
      for (folderPath <- folderPaths) {
        val split = folderPath.splitAt(folderPath.lastIndexOf("/"))
        if (!split._1.equals(""))
          foldersList += split._1 + "/"
      }
      foldersList.toList.distinct

P.S .: Блок улова намеренно отсутствует из-за неактуальности.

0 голосов
/ 27 августа 2018

Функция listObjects (и другие) разбивается на страницы, каждый раз возвращая до 100 записей.

Из документа:

Поскольку корзины могут содержать практически неограниченное количество ключей, Полные результаты запроса списка могут быть очень большими. Управлять Большие наборы результатов, Amazon S3 использует разбиение на страницы, чтобы разделить их на несколько ответов. Всегда проверяйте ObjectListing.isTruncated () метод, чтобы увидеть, если возвращенный листинг завершен или если дополнительные звонки необходимы, чтобы получить больше результатов. В качестве альтернативы используйте AmazonS3Client.listNextBatchOfObjects (ObjectListing) метод как простой способ получить следующую страницу списков объектов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...