Ответ 1
построение на sethwm ответе:
Чтобы получить каталоги верхнего уровня:
list(bucket.list("", "/"))
Чтобы получить подкаталоги files
:
list(bucket.list("files/", "/")
и т.д.
Я использую boto и python и amazon s3.
Если я использую
[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]
построение на sethwm ответе:
Чтобы получить каталоги верхнего уровня:
list(bucket.list("", "/"))
Чтобы получить подкаталоги files
:
list(bucket.list("files/", "/")
и т.д.
Как указано в одном из комментариев, предложенном j1m, возвращается префиксный объект. Если после имени/пути вы можете использовать переменную name. Например:
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
Это будет неполным ответом, поскольку я не знаю 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/files/" и разделителем "/", вы получите результаты:
mybucket/files/pdf/
И если вы перешли в СПИСОК с префиксом "mybucket/files/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, я понятия не имею. Надеюсь, есть способ пройти.
В принципе нет такой вещи, как папка в S3. Внутренне все хранится как ключ, и если имя ключа имеет в нем символ косой черты, клиенты могут решить показать его как папку.
С учетом этого вы должны сначала получить все ключи, а затем использовать регулярное выражение, чтобы отфильтровать пути, которые включают в себя косую черту. Решение, которое у вас есть прямо сейчас, является хорошим началом.
Я вижу, что вы успешно сделали соединение 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)
Интерфейс boto позволяет вам перечислить содержимое ведра и предоставить префикс записи. Таким образом, у вас может быть запись для каталога в обычном файле:
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
Проблема здесь, как было сказано другими, заключается в том, что папка не обязательно содержит ключ, поэтому вам придется искать строки для символа/и определять их папки через это. Здесь один из способов генерации рекурсивного словаря, имитирующего структуру папок.
Если вы хотите, чтобы все файлы и их 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
Затем это может быть рекурсивно прочитано позже.
Я нашел следующее, чтобы работать с Boto3:
def list_folders(s3_client, bucket_name):
response = s3_client.list_objects_v2(Bucket=bucket_name, Prefix='', Delimiter='/')
for content in response.get('CommonPrefixes', []):
yield content.get('Prefix')
s3_client = session.client('s3')
folder_list = list_folders(s3_client, bucket_name)
for folder in folder_list:
print('Folder found: %s' % folder)
Refs.:
Полный пример с 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")