web-dev-qa-db-fra.com

Comment obtenir la liste des seuls dossiers d'Amazon S3 en utilisant python boto

J'utilise boto et python et Amazon s3.

Si j'utilise

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

alors j'obtiens toutes les clés de tous les fichiers.

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/

quelle est la meilleure façon de

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

Je pense faire comme ça

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

en s'appuyant sur la réponse de sethwm:

Pour obtenir les répertoires de niveau supérieur:

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

Pour obtenir les sous-répertoires de files:

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

etc.

40
j1m

Comme indiqué dans l'un des commentaires, l'approche suggérée par j1m renvoie un objet préfixe. Si vous recherchez un nom/chemin, vous pouvez utiliser la variable nom. Par exemple:

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
17
Wawrzek

Cela va être une réponse incomplète car je ne sais pas python ou boto, mais je veux commenter le concept sous-jacent dans la question.

L'une des autres affiches avait raison: il n'y a pas de concept d'annuaire dans S3. Il n'y a que des paires clé/valeur plates. De nombreuses applications prétendent que certains délimiteurs indiquent des entrées de répertoire. Par exemple "/" ou "\". Certaines applications vont jusqu'à mettre un fichier factice en place de sorte que si le "répertoire" se vide, vous pouvez toujours le voir dans les résultats de la liste.

Vous n'avez pas toujours besoin de tirer l'ensemble de votre compartiment vers le bas et de filtrer localement. S3 a un concept de liste délimitée où vous spécifiez ce que vous jugeriez votre délimiteur de chemin ("/", "\", "|", "foobar", etc.) et S3 vous renverra des résultats virtuels, similaires à ce que vous vouloir.

http://docs.aws.Amazon.com/AmazonS3/latest/API/RESTBucketGET.html (Regardez l'en-tête du délimiteur.)

Cette API vous obtiendra un niveau de répertoires. Donc, si vous aviez dans votre exemple:

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/

Et vous avez passé dans une LISTE avec le préfixe "" et le délimiteur "/", vous obtiendrez des résultats:

mybucket/files/

Si vous passez dans une LISTE avec le préfixe "mybucket/files /" et le délimiteur "/", vous obtiendrez des résultats:

mybucket/files/pdf/

Et si vous passiez dans une LISTE avec le préfixe "mybucket/files/pdf /" et le délimiteur "/", vous obtiendriez des résultats:

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/

Vous seriez seul à ce moment-là si vous vouliez éliminer les fichiers pdf eux-mêmes de l'ensemble de résultats.

Maintenant, comment vous faites cela en python/boto, je ne sais pas. Espérons qu'il existe un moyen de passer.

13
sethwm

Fondamentalement, il n'existe pas de dossier dans S3. En interne, tout est stocké sous forme de clé et si le nom de la clé contient un caractère barre oblique, les clients peuvent décider de l'afficher sous forme de dossier.

Dans cet esprit, vous devez d'abord obtenir toutes les clés, puis utiliser une expression régulière pour filtrer les chemins qui contiennent une barre oblique. La solution que vous avez en ce moment est déjà un bon début.

8
j0nes

Je vois que vous avez réussi à établir la connexion boto. Si vous n'avez qu'un seul répertoire qui vous intéresse (comme vous l'avez indiqué dans l'exemple), je pense que ce que vous pouvez faire est d'utiliser le préfixe et le délimiteur qui sont déjà fournis via AWS ( Link ).

Boto utilise cette fonctionnalité dans son objet bucket et vous pouvez récupérer les informations d'un répertoire hiérarchique à l'aide du préfixe et du délimiteur. Le bucket.list () renverra un objet boto.s3.bucketlistresultset.BucketListResultSet.

J'ai essayé ceci de plusieurs façons, et si vous choisissez d'utiliser un argument delimiter= Dans bucket.list(), l'objet renvoyé est un itérateur pour boto.s3.prefix.Prefix, Plutôt que boto.s3.key.Key. En d'autres termes, si vous essayez de récupérer les sous-répertoires, vous devez mettre delimiter='\' Et en conséquence, vous obtiendrez un itérateur pour l'objet prefix

Les deux objets retournés (préfixe ou objet clé) ont un attribut .name, Donc si vous voulez les informations de répertoire/fichier sous forme de chaîne, vous pouvez le faire en imprimant comme ci-dessous:

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)
5
Erica Jh Lee

l'interface boto vous permet de lister le contenu d'un bucket et de donner un préfixe de l'entrée. De cette façon, vous pouvez avoir l'entrée pour ce qui serait un répertoire dans un système de fichiers normal:

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
2
bambata

Le problème ici, comme cela a été dit par d'autres, est qu'un dossier n'a pas nécessairement de clé, vous devez donc rechercher dans les chaînes le caractère/et trouver vos dossiers à travers cela. Voici une façon de générer un dictionnaire récursif imitant une structure de dossiers.

Si vous voulez que tous les fichiers et leurs URL soient dans les dossiers

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

Si vous voulez juste les dossiers vides

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

Cela peut ensuite être lu récursivement plus tard.

2
Nathan Hazzard

J'ai trouvé ce qui suit pour fonctionner avec 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)

Réf.:

2
Eduardo Sztokbant