Amazon S3: как получить список папок в ведре?

Все, что я нашел, это метод GET Bucket Но я не могу понять, как я могу получить только список папок в текущей папке. Какой префикс и разделитель мне нужно использовать? Это вообще возможно?


person kkost    schedule 05.11.2015    source источник


Ответы (5)


В качестве примера предположим, что у меня есть корзина в области USEast1 с именем MyBucketName со следующими ключами:

 temp/
 temp/foobar.txt
 temp/txt/
 temp/txt/test1.txt
 temp/txt/test2.txt
 temp2/

Работа с папками может сбивать с толку, потому что S3 изначально не поддерживает иерархическую структуру - скорее, это просто ключи, как и любой другой объект S3. Папки - это просто абстракция, доступная в веб-консоли S3, чтобы упростить навигацию по корзине. Поэтому, когда мы работаем программно, мы хотим найти ключи, соответствующие размерам «папки» (разделитель «/», размер = 0), потому что они, скорее всего, будут «папками», представленными нам консолью S3.

Примечание для обоих примеров: я использую пакет NuGet AWSSDK.S3 версии 3.1.

Пример 1. Все папки в корзине

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

IAmazonS3 client;
using (client = new AmazonS3Client(Amazon.RegionEndpoint.USEast1))
{
    // Build your request to list objects in the bucket
    ListObjectsRequest request = new ListObjectsRequest
    {
        BucketName = "MyBucketName"
    };

    do
    {
        // Build your call out to S3 and store the response
        ListObjectsResponse response = client.ListObjects(request);

        // Filter through the response to find keys that:
        // - end with the delimiter character '/' 
        // - are empty. 
        IEnumerable<S3Object> folders = response.S3Objects.Where(x =>
            x.Key.EndsWith(@"/") && x.Size == 0);

        // Do something with your output keys.  For this example, we write to the console.
        folders.ToList().ForEach(x => System.Console.WriteLine(x.Key));

        // If the response is truncated, we'll make another request 
        // and pull the next batch of keys
        if (response.IsTruncated)
        {
            request.Marker = response.NextMarker;
        }
        else
        {
            request = null;
        }
    } while (request != null);
}

Ожидаемый вывод на консоль:

temp/
temp/txt/
temp2/

Пример 2. Папки, соответствующие указанному префиксу

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

ListObjectsRequest request = new ListObjectsRequest
    {
        BucketName = "MyBucketName",
        Prefix = "temp/"
    };

Применительно к примеру 1 мы ожидаем следующий результат:

temp/
temp/txt/

Дополнительная литература:

person Anthony Neace    schedule 05.11.2015
comment
Спасибо за подробный ответ. Этот код работает для меня, когда я меняю x.Size == 0 на x.Size == 1. Но он не распознает все папки, а только небольшую их часть. Я не могу понять, почему это происходит. Я ровно то, что мой цикл повторяется снова и снова, пока не дойдет до конца. Но я не могу получить все папки. В чем может быть причина? - person kkost; 05.11.2015
comment
Может быть, это связано с тем, что вы изменили размер на 1? «Папки» представлены в этом вызове списка как объекты S3 без содержимого: они должны иметь размер 0. Вы можете просто удалить размер из предиката, если найдете нужные объекты без него. - person Anthony Neace; 05.11.2015
comment
Если после этого у вас все еще возникают проблемы, возможно, убедитесь, что ваш ListObjectsRequest не слишком ограничивает ваш запрос. Например, если вы указали префикс ... проверьте свой код без него, чтобы убедиться, что он не слишком ограничивает ваш запрос. Если это не сработает, не стесняйтесь задать новый вопрос (этот вопрос очень ясный, мы не хотим загромождать его) с примером структуры вашего ведра и запросом, который вы пытаетесь сделать. . - person Anthony Neace; 05.11.2015
comment
Если я попытаюсь удалить сравнение размеров, я получу тот же результат, когда напишу x.Size == 1. Можете ли вы посмотреть мой код с моими результатами? codehare.io/4eBiJ Вот как это должно выглядеть: snag.gy/HbLhK.jpg - person kkost; 05.11.2015
comment
request.Delimiter не является необходимым и может вызывать проблемы, попробуйте без этого. Интересно, что BF/Music/, кажется, сразу пропускают; не могли бы вы выполнить проверку работоспособности и убедиться, что он существует, как вы ожидаете, в ведре S3? Что касается подкаталогов, если они вам не нужны, вы можете просто отфильтровать свой список дальше после извлечения с помощью регулярного выражения или сопоставления с одной косой чертой и т. Д. - person Anthony Neace; 05.11.2015
comment
Я полностью уверен, что этот каталог существует. Также под каталогами, которые отображаются в результате запроса, существует множество папок. Но отображались только BF / REFERENCE_TRACKS / и BF / REFERENCE_TRACKS / MP3 /. Дочерних каталогов много, но они не отображаются. - person kkost; 05.11.2015
comment
Позвольте нам продолжить это обсуждение в чате. - person kkost; 05.11.2015
comment
@AnthonyNeace Я получаю сообщение об ошибке http://stackoverflow.com/questions/39106395/amazon-s3-list-objects?noredirect=1#comment65572638_39106395 - person DarkMakukudo; 24.08.2016

Используя prefix из the/path/to/read/ (обратите внимание, что нет ведущей косой черты, но есть замыкающая косая черта) и delimiter из /, вы найдете все папки в этой папке внутри <CommonPrefixes>.

CommonPrefixes

Ответ может содержать CommonPrefixes, только если вы укажете разделитель. Когда вы это сделаете, CommonPrefixes будет содержать все (если есть) ключи между префиксом и следующим вхождением строки, указанной разделителем. Фактически CommonPrefixes перечисляет ключи, которые действуют как подкаталоги в каталоге, указанном Prefix. Например, если префикс - это примечания /, а разделитель - это косая черта (/), в примечаниях / лето / июль общий префикс - ноты / лето /. Все ключи, объединенные в общий префикс, считаются одним возвратом при подсчете количества возвратов. См. MaxKeys.

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

person Michael - sqlbot    schedule 05.11.2015

В качестве альтернативы другой более простой подход - использовать https://github.com/minio/minio-dotnet.

Minio .Net реализует минимальные API для работы с Amazon S3 и другими совместимыми решениями для хранения данных.

В следующем примере показано, как можно отфильтровать только каталоги. Здесь CommonPrefix абстрагируется как папка через API ListObjects ().

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Minio;
using Minio.Xml;

namespace Minio.Examples
{
    class ListObjects
    {
        static int Main(string[] args)
        {
            var client = new MinioClient("https://s3.amazonaws.com", "ACCESSKEY", "SECRETKEY");

            var items = client.ListObjects("bucket");

            foreach (Item item in items)
            {
                if (item.IsDir)
                {
                    Console.Out.WriteLine("{0}", item.Key);
                }
            }
            return 0;
        }
    }
}
person Harshavardhana    schedule 07.11.2015

Чего Энтони здесь не хватает, так это того, что папка не обязательно имеет связанный с ней ключ. Если файл создается в S3 и ему задан ключ вроде «folder / name.ext», S3 отобразит папку «folder», но у него нет ключа, что означает, что вы не получите его в своих результатах.

Единственный способ поймать эти папки - посмотреть на сами ключи и повторно выразить имя ключа для символа «/». Если бы я знал C # немного лучше, я бы написал вам образец кода, но для справки вот пример Python, который я написал по другому вопросу.

person Nathan Hazzard    schedule 20.01.2017

Добавление разделителя '/' к моим параметрам помогло мне.

Если кому-то нужно решение NodeJS, вот что я использовал:

listdelim: function (path) {
    const params = {
        Bucket: process.env['bucket'],
        MaxKeys: 1000,
        Prefix: path,
        Delimiter: '/'
    }
    return new Promise((resolve, reject) => {
        s3.listObjectsV2(params, function (err, data) {
            if (err) {
                console.log(err, err.stack)
                reject(err)
            } else {
                resolve(data)
            }
        })
    })
}
person Brett Schmidt    schedule 12.01.2020