Amazon S3 boto - come eliminare la cartella?


87

Ho creato una cartella in s3 denominata "test" e ho inserito "test_1.jpg", "test_2.jpg" in "test".

Come posso utilizzare boto per eliminare la cartella "test"?


1
@pyCthon Tecnologia sbagliata. Riprova.
devinbost

Risposte:


61

Non ci sono non le cartelle in S3. Invece, le chiavi formano uno spazio dei nomi piatto. Tuttavia, una chiave con barre nel nome viene visualizzata specialmente in alcuni programmi, inclusa la console AWS (vedi ad esempio Amazon S3 boto - come creare una cartella? ).

Invece di eliminare "una directory", puoi (e devi) elencare i file per prefisso ed eliminare. In sostanza:

for key in bucket.list(prefix='your/directory/'):
    key.delete()

Tuttavia, le altre risposte complete in questa pagina presentano approcci più efficienti.


Si noti che la ricerca del prefisso viene eseguita utilizzando la ricerca di stringhe fittizie. Se il prefisso fosse your/directory, cioè, senza la barra finale aggiunta, anche il programma eliminerebbe felicemente your/directory-that-you-wanted-to-remove-is-definitely-not-t‌​his-one.

Per ulteriori informazioni, vedere Le chiavi dell'elenco boto S3 a volte restituiscono la chiave della directory.


1
Come eliminare la directory? Se questa directory verrà eliminata automaticamente quando tutti i file in questa directory verranno eliminati?
wade huang

Grazie .. L'ho finito ~
wade huang

@wadehuang - potresti condividere il tuo codice sull'eliminazione delle cartelle?
Letc

Come eliminare i file nella cartella di s3 che hanno 2 giorni in Python. ho questo nel mio s3 - bucket / 1 / backups / (10 file) è necessario rimuovere tutti i file che hanno due giorni di vita
艾瑪艾瑪 艾瑪

202

Ecco la versione 2018 (quasi 2019):

s3 = boto3.resource('s3')
bucket = s3.Bucket('mybucket')
bucket.objects.filter(Prefix="myprefix/").delete()

27
Questa è di gran lunga la migliore risposta.
user554481

2
qualcuno potrebbe trovare utile sapere che bucket.objects.all (). delete () svuota l'intero bucket senza eliminarlo, non importa quanti oggetti ci siano (cioè non è interessato ma il limite di 1000 elementi). Vedi: boto3.amazonaws.com/v1/documentation/api/latest/reference/…
fabiog

1
Ciao Raz, questo non funziona per me, ottengo semplicemente parentesi quadre vuote, ovvero []
Soyf

Purtroppo, questo non supporta il suffisso :(
Anum Sheraz

La cosa fantastica è che questa soluzione funziona anche con più di 1000 oggetti
Mabyn

46

Sento che è passato un po 'di tempo e boto3 ha diversi modi per raggiungere questo obiettivo. Questo presuppone che tu voglia eliminare la "cartella" di prova e tutti i suoi oggetti. Ecco un modo:

s3 = boto3.resource('s3')
objects_to_delete = s3.meta.client.list_objects(Bucket="MyBucket", Prefix="myfolder/test/")

delete_keys = {'Objects' : []}
delete_keys['Objects'] = [{'Key' : k} for k in [obj['Key'] for obj in objects_to_delete.get('Contents', [])]]

s3.meta.client.delete_objects(Bucket="MyBucket", Delete=delete_keys)

Questo dovrebbe fare due richieste, una per recuperare gli oggetti nella cartella, la seconda per eliminare tutti gli oggetti in detta cartella.

https://boto3.readthedocs.org/en/latest/reference/services/s3.html#S3.Client.delete_objects


Questa è di gran lunga la soluzione più veloce.
elemento profondo

2
Questa è la soluzione più veloce, ma tieni presente che list_objectsnon può restituire più di 1000 chiavi, quindi devi eseguire questo codice più volte.
schiavo della lampada

4
Puoi usare il paginator se hai più di 1k oggetti - vedi la mia risposta sotto.
dmitrybelyakov

@deepelement, e funziona solo in boto3, non boto
avocado

1
Questa grande opera, ed è possibile eseguirlo da una lambda Python mettendo il codice di cui sopra in una funzione lambda_handler: import boto3; def lambda_handler(event, context): '''Code from above'''. Assicurati di concedere al tuo Lambda l'autorizzazione per eliminare da S3 ed estendere il timeout.
Nadir Sidi

21

Puoi usare bucket.delete_keys () con un elenco di chiavi (con un numero elevato di chiavi ho riscontrato che questo è un ordine di grandezza più veloce rispetto all'utilizzo di key.delete).

Qualcosa come questo:

delete_key_list = []
for key in bucket.list(prefix='/your/directory/'):
    delete_key_list.append(key)
    if len(delete_key_list) > 100:
        bucket.delete_keys(delete_key_list)
        delete_key_list = []

if len(delete_key_list) > 0:
    bucket.delete_keys(delete_key_list)

20

Un leggero miglioramento rispetto alla soluzione di Patrick. Come forse saprai, entrambi list_objects()e delete_objects()hanno un limite di 1000 oggetti. Questo è il motivo per cui devi impaginare l'elenco ed eliminare in blocchi. Questo è abbastanza universale e si può dare Prefixa paginator.paginate()sottodirectory cancellare / percorsi

client = boto3.client('s3', **credentials)
paginator = client.get_paginator('list_objects_v2')
pages = paginator.paginate(Bucket=self.bucket_name)

delete_us = dict(Objects=[])
for item in pages.search('Contents'):
    delete_us['Objects'].append(dict(Key=item['Key']))

    # flush once aws limit reached
    if len(delete_us['Objects']) >= 1000:
        client.delete_objects(Bucket=bucket, Delete=delete_us)
        delete_us = dict(Objects=[])

# flush rest
if len(delete_us['Objects']):
    client.delete_objects(Bucket=bucket, Delete=delete_us)

2
E se vuoi limitare a una "directory" usa la Prefixparola chiave in paginator.paginate()Vedi tutte le opzioni: boto3.readthedocs.io/en/latest/reference/services/…
Chad

1
con il Prefixfiltro suggerito da @Chad , ho dovuto aggiungere un if item is not Nonecontrollo prima della cancellazione (poiché alcuni dei miei prefissi S3 non esistevano / non avevano oggetti)
y2k-shubham

3

Se il controllo delle versioni è abilitato nel bucket S3:

s3 = boto3.resource('s3')
bucket = s3.Bucket('mybucket')
bucket.object_versions.filter(Prefix="myprefix/").delete()

C'è un modo per stampare qualcosa fuori di ciò che viene cancellato? Voglio eliminare prima le versioni e poi quella attuale. ex bucket.objects.filter (Prefix = "myprefix /"). delete (); in questo momento vedo solo un cursore lampeggiante e non so cosa sta succedendo.
DJ_Stuffy_K

1
Dovresti fare qualcosa come files_to_delete = bucket.object_versions.filter(Prefix="myprefix/")poi iterare files_to_deletee chiamare print () quindi delete () su di loro.
Dan-Dev

1

Se è necessario filtrare per contenuto oggetto come ho fatto io, il seguente è un modello per la tua logica:

def get_s3_objects_batches(s3: S3Client, **base_kwargs):
    kwargs = dict(MaxKeys=1000, **base_kwargs)
    while True:
        response = s3.list_objects_v2(**kwargs)
        # to yield each and every file: yield from response.get('Contents', [])
        yield response.get('Contents', [])
        if not response.get('IsTruncated'):  # At the end of the list?
            break
        continuation_token = response.get('NextContinuationToken')
        kwargs['ContinuationToken'] = continuation_token


def your_filter(b):
   raise NotImplementedError()


session = boto3.session.Session(profile_name=profile_name)
s3client = session.client('s3')
for batch in get_s3_objects_batches(s3client, Bucket=bucket_name, Prefix=prefix):
    to_delete = [{'Key': obj['Key']} for obj in batch if your_filter(obj)]
    if to_delete:
        s3client.delete_objects(Bucket=bucket_name, Delete={'Objects': to_delete})
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.