2013-06-28 2 views
26

Я использую boto и python и amazon s3.Как получить список только папок в amazon S3 с помощью python boto

Если я использую

[key.name for key in list(self.bucket.list())]

тогда я получить все ключи от всех файлов.

mybucket/files/pdf/abc.pdf 
mybucket/files/pdf/abc2.pdf 
mybucket/files/pdf/abc3.pdf 
mybucket/files/pdf/abc4.pdf 
mybucket/files/pdf/new/ 
mybucket/files/pdf/new/abc.pdf 
mybucket/files/pdf/2011/ 

, что это лучший способ

1. either get all folders from s3 
2. or from that list just remove the file from the last and get the unique keys of folders 

Я имею в виду сделать как этот

set([re.sub("/[^/]*$","/",path) for path in mylist] 

ответ

7

В принципе нет такой вещи, как папка в S3. Внутренне все хранится как ключ, и если в имени ключа есть символ косой черты, клиенты могут решить показать его как папку.

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

10

Это будет неполным ответом, поскольку я не знаю python или boto, но хочу прокомментировать базовую концепцию в вопросе.

Один из других плакатов был прав: в S3 нет концепции каталога. Есть только плоские пары ключ/значение. Многие приложения притворяются, что определенные разделители указывают записи каталога. Например, «/» или «\». Некоторые приложения заходят так далеко, как помещают фиктивный файл на место, так что, если «каталог» опустеет, вы все равно можете увидеть его в результатах списка.

Вам не всегда нужно тянуть все ваше ведро и делать фильтрацию локально. S3 имеет концепцию списка с разделителями, в котором вы конкретно определяете свой разделитель пути («/», «\», «|», «foobar» и т. Д.), А S3 вернет вам виртуальные результаты, аналогичные тому, что вы хотеть.

http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketGET.html ( Посмотрите на заголовок разделителем.)

Этот API поможет вам один уровень каталогов. Так что если у вас в вашем примере:

mybucket/files/pdf/abc.pdf 
mybucket/files/pdf/abc2.pdf 
mybucket/files/pdf/abc3.pdf 
mybucket/files/pdf/abc4.pdf 
mybucket/files/pdf/new/ 
mybucket/files/pdf/new/abc.pdf 
mybucket/files/pdf/2011/ 

И вы прошли в список с префиксом «» и разделителем «/», вы получите результаты:

mybucket/files/ 

Если вы прошли в СПИСКА с приставкой «mybucket/файлов /» и разделителем «/», вы получите результаты:

mybucket/files/pdf/ 

и если вы прошли в список с префиксом «mybucket/файлы/PDF /» и разделителем «/», вы получите результаты:

mybucket/files/pdf/abc.pdf 
mybucket/files/pdf/abc2.pdf 
mybucket/files/pdf/abc3.pdf 
mybucket/files/pdf/abc4.pdf 
mybucket/files/pdf/new/ 
mybucket/files/pdf/2011/ 

Если вы хотите удалить сами файлы PDF из набора результатов, вы сами по себе должны быть сами по себе.

Теперь, как вы это делаете в python/boto Я понятия не имею. Надеюсь, есть способ пройти.

+1

Почему 'новых/а.pdf' с разделителем '/' во втором примере с префиксом 'mybucket/files/pdf /'. Я полагаю, что с разделителем '/' его внутренний объект и не должен быть указан. @sethwm – xtreak

+0

@Wordzilla, это ошибка. Спасибо, что поймали его. – sethwm

+0

Спасибо. Это было полезно для меня в моем скрипте сегодня :) – xtreak

3

Интерфейс boto позволяет вам перечислить содержимое ведра и предоставить префикс записи. Таким образом, вы можете иметь вход для того, что бы каталог в нормальном filesytem:

import boto 
AWS_ACCESS_KEY_ID = '...' 
AWS_SECRET_ACCESS_KEY = '...' 

conn = boto.connect_s3(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) 
bucket = conn.get_bucket() 
bucket_entries = bucket.list(prefix='/path/to/your/directory') 

for entry in bucket_entries: 
    print entry 
+1

В нем перечислены все каталоги и файлы в этом префиксном пути – RexFuzzle

39

здание на ответ sethwm в:

Чтобы получить верхние каталоги уровня:

list(bucket.list("", "/")) 

К получить подкаталоги из files:

list(bucket.list("files/", "/") 

и так далее.

+2

Это замечательно, и документы, безусловно, привели меня в этом направлении, но я, похоже, не получаю список ключей. Вместо этого я получаю список с ключом и объект 'boto.s3.prefix.Prefix()', который я действительно не знаю, что с ним делать. Есть идеи? – brice

+0

bucket.list дает список префиксных объектов. Атрибут 'name' - это, вероятно, то, что вы ищете. –

+1

Важно отметить, что для получения каталогов «префикс» (первый параметр) должен заканчиваться разделителем –

14

Как указано в одном из подходов, предложенных j1m, возвращается префиксный объект. Если вы после имени/пути, вы можете использовать переменную имя. Например:

import boto 
import boto.s3 

conn = boto.s3.connect_to_region('us-west-2') 
bucket = conn.get_bucket(your_bucket) 

folders = bucket.list("","/") 
for folder in folders: 
    print folder.name 
+0

. Если вы хотите получить все свои ковши, вы можете обернуть это в ведра = conn.get_all_buckets, а затем для ведра в ведрах: а затем продолжить с bucket.list .... например >>> buckets = S3Connection(). get_all_buckets() >>> для ведра в ковши: ... для папки в bucket.list(): ... print folder.name – cgseller

2

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

Если вы хотите, чтобы все файлы и их URL, в папках

assets = {} 
    for key in self.bucket.list(str(self.org) + '/'): 
    path = key.name.split('/') 

    identifier = assets 
    for uri in path[1:-1]: 
    try: 
     identifier[uri] 
    except: 
     identifier[uri] = {} 
    identifier = identifier[uri] 

    if not key.name.endswith('/'): 
     identifier[path[-1]] = key.generate_url(expires_in=0, query_auth=False) 

return assets 

Если вы хотите просто пустые папки

folders = {} 
    for key in self.bucket.list(str(self.org) + '/'): 
    path = key.name.split('/') 

    identifier = folders 
    for uri in path[1:-1]: 
    try: 
     identifier[uri] 
    except: 
     identifier[uri] = {} 
    identifier = identifier[uri] 

    if key.name.endswith('/'): 
     identifier[path[-1]] = {} 

return folders 

Это может быть затем рекурсивно прочитать позже.

3

Я вижу, что вы успешно сделали соединение boto. Если у вас есть только один каталог, который вас интересует (например, вы указали в примере), я думаю, что вы можете использовать префикс и разделитель, которые уже предоставляются через AWS (Link).

Boto использует эту функцию в своем ведомом объекте, и вы можете получить информацию о иерархическом каталоге, используя префикс и разделитель. Команда bucket.list() вернет объект boto.s3.bucketlistresultset.BucketListResultSet.

Я попытался это пару путей, и если вы решите использовать delimiter= аргумент в bucket.list(), возвращаемый объект итератора для boto.s3.prefix.Prefix, а не boto.s3.key.Key. Другими словами, если вы пытаетесь получить подкаталоги, вы должны поставить delimiter='\' и в результате вы получите итератор для prefix объекта

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

from boto.s3.connection import S3Connection 

key_id = '...' 
secret_key = '...' 

# Create connection 
conn = S3Connection(key_id, secret_key) 

# Get list of all buckets 
allbuckets = conn.get_all_buckets() 
for bucket_name in allbuckets: 
    print(bucket_name) 

# Connet to a specific bucket 
bucket = conn.get_bucket('bucket_name') 

# Get subdirectory info 
for key in bucket.list(prefix='sub_directory/', delimiter='/'): 
    print(key.name) 
+0

Хотя этот фрагмент кода приветствуется, и может оказать некоторую помощь, было бы [значительно улучшено, если бы оно включало объяснение] (// meta.stackexchange.com/q/114762) * как * и * почему * это решает проблему. Помните, что вы отвечаете на вопрос читателей в будущем, а не только на человека, который спрашивает сейчас! Пожалуйста, отредактируйте свой ответ, чтобы добавить объяснение, и укажите, какие ограничения и допущения применяются. –

+0

@TobySpeight, я добавил дополнительную информацию. Спасибо за ваш комментарий. –

-1

Полного пример с boto3 с помощью клиента S3

import boto3 


def list_bucket_keys(bucket_name): 
    s3_client = boto3.client("s3") 
    """ :type : pyboto3.s3 """ 
    result = s3_client.list_objects(Bucket=bucket_name, Prefix="Trails/", Delimiter="/") 
    return result['CommonPrefixes'] 


if __name__ == '__main__': 
    print list_bucket_keys("my-s3-bucket-name")