2016-03-04 28 views
13

Utilizzando boto3, posso accedere al mio AWS S3 secchio:Recupero nomi sottocartelle nella S3 secchio da boto3

s3 = boto3.resource('s3') 
bucket = s3.Bucket('my-bucket-name') 

Ora, il secchio contenente la cartella first-level, che a sua volta contiene diverse sottocartelle denominate con un timestamp, per istanza 1456753904534. Ho bisogno di conoscere il nome di queste sotto-cartelle per un altro lavoro che sto facendo e mi chiedo se potrei avere boto3 recuperarle per me.

Così ho provato:

objs = bucket.meta.client.list_objects(Bucket='my-bucket-name') 

che dà un dizionario, la cui chiave 'Contenuto' mi dà tutti i file di terzo livello, invece delle directory timestamp di secondo livello, infatti ho ottenere una lista contenente le cose come

{u'ETag ': ' "ETAG"', u'Key': primo livello/1.456.753,904534 millions/part-00014' , u'LastModified ': datetime.datetime (2016, 2, 29 , 13, 52, 24, tzinfo = tzutc()),
u'Owner ': {u'DisplayName': 'owner', u'ID ': 'id'},
u'Size ': dimensione, u'StorageClass': 'Stoccaggio'}

si può vedere che i file specifici, in questo caso part-00014 vengono recuperati, mentre mi piacerebbe per ottenere il nome della directory da solo. In linea di principio potrei togliere il nome della directory da tutti i percorsi ma è brutto e costoso recuperare tutto al terzo livello per ottenere il secondo livello!

Ho anche provato qualcosa riferito here:

for o in bucket.objects.filter(Delimiter='/'): 
    print(o.key) 

ma non ho ricevuto le cartelle al livello desiderato.

C'è un modo per risolvere questo?

+0

Quindi stai dicendo che [questa] (https://github.com/boto/boto3/issues/134 # issuecomment-116766812) non funziona? Potresti postare cosa succede quando lo esegui? –

+1

@JordonPhillips Ho provato le prime righe del link che hai inviato, che ho incollato qui, e ottengo i file di testo al primo livello del bucket e nessuna cartella. –

+0

@mar tin Hai mai risolto questo problema. Sto affrontando un dilemma simile in cui ho bisogno del primo elemento in ogni sottocartella di bucket. –

risposta

8

S3 è una memoria oggetto, esso non hanno un reale struttura di directory. "/" È piuttosto cosmetico. Una ragione per cui le persone vogliono avere una struttura di directory, perché possono mantenere/sfoltire/aggiungere una struttura all'applicazione. Per S3, tratti questa struttura come una sorta di indice o tag di ricerca.

Per manipolare l'oggetto in S3, è necessario boto3.client o boto3.resource, ad es. Per elencare tutti gli oggetti

import boto3 
s3 = boto3.client("s3") 
all_objects = s3.list_objects(Bucket = 'my-bucket-name') 

http://boto3.readthedocs.org/en/latest/reference/services/s3.html#S3.Client.list_objects

un promemoria su boto3: boto3.resource è un bel API di alto livello. Ci sono pro e contro usando boto3.client vs boto3.resource. Se si sviluppa una libreria condivisa interna, utilizzando boto3.resource si otterrà un livello blackbox sulle risorse utilizzate.

+1

Questo mi dà lo stesso risultato che ottengo con il mio tentativo nella domanda. Suppongo che dovrò risolvere il difficile prendendo tutte le chiavi dagli oggetti restituiti e dividendo la stringa per ottenere il nome della cartella. –

+1

@martina: un pigro pigro si divide e raccoglie gli ultimi dati all'interno dell'elenco, ad es. nomefile = keyname.split ("/") [- 1] – mootmoot

+1

@martin 'nome_directory = os.path.dirname (directory/percorso/e/nomefile.txt)' e 'file_name = os.path.basename (directory/percorso/e/nomefile.txt) ' – jkdev

1

Prima di tutto, non esiste un concetto di cartella reale in S3. È possibile avere un file @'/folder/subfolder/myfile.txt' e nessuna cartella o sottocartella.

Per "simulare" una cartella in S3, è necessario creare un file vuoto con un '/' alla fine del suo nome (vedi Amazon S3 boto - how to create a folder?)

per il vostro problema, probabilmente si dovrebbe utilizzare il metodo get_all_keys con 2 parametri: prefix e delimiter

https://github.com/boto/boto/blob/develop/boto/s3/bucket.py#L427

for key in bucket.get_all_keys(prefix='first-level/', delimiter='/'): 
    print(key.name) 
+0

Ho paura di non avere il metodo get_all_keys sull'oggetto bucket. Sto usando la versione 1.2.3 di boto3. –

+0

Appena controllato boto 1.2a: lì, bucket ha un metodo 'list' con' prefix' e 'delimiter'. Suppongo che dovrebbe funzionare. – Pirheas

+1

L'oggetto Bucket recuperato come post nella domanda non ha quei metodi. Sono su boto3 1.2.6, a quale versione si riferisce il tuo link? –

23

Sotto il pezzo di codice restituisce SOLO le "sottocartelle" in una "cartella" dal secchio s3.

import boto3 
bucket = 'my-bucket' 
#Make sure you provide/in the end 
prefix = 'prefix-name-with-slash/' 

client = boto3.client('s3') 
result = client.list_objects(Bucket=bucket, Prefix=prefix, Delimiter='/') 
for o in result.get('CommonPrefixes'): 
    print 'sub folder : ', o.get('Prefix') 

Per ulteriori informazioni, è possibile consultare https://github.com/boto/boto3/issues/134

+0

Cosa fare se voglio elencare i contenuti di una particolare sottocartella? –

8

Mi c'è voluto un sacco di tempo per capire, ma finalmente ecco un modo semplice per elencare il contenuto di una sottocartella nel bucket S3 utilizzando boto3. Speranza che aiuta

prefix = "folderone/foldertwo/" 
s3 = boto3.resource('s3') 
bucket = s3.Bucket(name="bucket_name_here") 
FilesNotFound = True 
for obj in bucket.objects.filter(Prefix=prefix): 
    print('{0}:{1}'.format(bucket.name, obj.key)) 
    FilesNotFound = False 
if FilesNotFound: 
    print("ALERT", "No file in {0}/{1}".format(bucket, prefix)) 
1

L'AWS cli fa (presumibilmente senza caricare e iterazione attraverso tutte le chiavi nel secchio) quando si esegue aws s3 ls s3://my-bucket/, così ho pensato che ci deve essere un modo utilizzando boto3.

https://github.com/aws/aws-cli/blob/0fedc4c1b6a7aee13e2ed10c3ada778c702c22c3/awscli/customizations/s3/subcommands.py#L499

Sembra che effettivamente usano Prefisso e Delimitatore - sono stato in grado di scrivere una funzione che mi otterrebbe tutte le directory al livello principale di un secchio modificando il codice un po ':

def list_folders_in_bucket(bucket): 
    paginator = boto3.client('s3').get_paginator('list_objects') 
    folders = [] 
    iterator = paginator.paginate(Bucket=bucket, Prefix='', Delimiter='/', PaginationConfig={'PageSize': None}) 
    for response_data in iterator: 
     prefixes = response_data.get('CommonPrefixes', []) 
     for prefix in prefixes: 
      prefix_name = prefix['Prefix'] 
      if prefix_name.endswith('/'): 
       folders.append(prefix_name.rstrip('/')) 
    return folders 
1

le seguenti opere per me ... oggetti S3:

s3://bucket/ 
    form1/ 
     section11/ 
      file111 
      file112 
     section12/ 
      file121 
    form2/ 
     section21/ 
      file211 
      file112 
     section22/ 
      file221 
      file222 
      ... 
     ... 
    ... 

Uso:

from boto3.session import Session 
s3client = session.client('s3') 
resp = s3client.list_objects(Bucket=bucket, Prefix='', Delimiter="/") 
forms = [x['Prefix'] for x in resp['CommonPrefixes']] 

otteniamo:

form1/ 
form2/ 
... 

Con:

resp = s3client.list_objects(Bucket=bucket, Prefix='form1/', Delimiter="/") 
sections = [x['Prefix'] for x in resp['CommonPrefixes']] 

otteniamo:

form1/section11/ 
form1/section12/ 
Problemi correlati