Amazon S3 boto - bagaimana cara menghapus folder?

87

Saya membuat folder di s3 bernama "test" dan saya mendorong "test_1.jpg", "test_2.jpg" ke dalam "test".

Bagaimana cara menggunakan boto untuk menghapus folder "test"?

mengarungi huang
sumber
1
Teknologi @pyCthon Salah. Coba lagi.
devinbost

Jawaban:

61

Tidak ada folder di S3. Sebaliknya, kunci membentuk namespace datar. Namun kunci dengan garis miring pada namanya ditampilkan secara khusus di beberapa program, termasuk konsol AWS (lihat misalnya Amazon S3 boto - bagaimana cara membuat folder? ).

Alih-alih menghapus "direktori", Anda dapat (dan harus) membuat daftar file dengan awalan dan menghapus. Intinya:

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

Namun jawaban lain yang berhasil di halaman ini menampilkan pendekatan yang lebih efisien.


Perhatikan bahwa awalan hanya dicari menggunakan pencarian string dummy. Jika awalannya your/directory, yaitu, tanpa menambahkan garis miring, program juga akan dengan senang hati menghapusnya your/directory-that-you-wanted-to-remove-is-definitely-not-t‌​his-one.

Untuk informasi selengkapnya, lihat kunci daftar boto S3 terkadang mengembalikan kunci direktori.

Antti Haapala
sumber
1
Bagaimana cara menghapus direktori? Jika direktori ini akan dihapus secara otomatis ketika semua file di direktori ini dihapus?
mengarungi huang
Terima kasih .. Saya telah menyelesaikannya ~
wade huang
@wadehuang - dapatkah Anda membagikan kode Anda tentang menghapus folder?
maric
Cara menghapus file di folder s3 yang berumur 2 hari di python. miliki ini di s3 saya - bucket / 1 / backups / (10 file) perlu menghapus semua file yang berusia dua hari
艾瑪艾瑪 艾瑪
202

Ini adalah versi 2018 (hampir 2019):

s3 = boto3.resource('s3')
bucket = s3.Bucket('mybucket')
bucket.objects.filter(Prefix="myprefix/").delete()
Raz
sumber
27
Sejauh ini, ini adalah jawaban terbaik.
pengguna554481
2
mungkin berguna bagi seseorang untuk mengetahui bahwa bucket.objects.all (). delete () mengosongkan seluruh bucket tanpa menghapusnya, tidak peduli berapa banyak objek yang ada (yaitu tidak terpengaruh tetapi dibatasi 1000 item). Lihat: boto3.amazonaws.com/v1/documentation/api/latest/reference/…
fabiog
1
Hai Raz, ini tidak berhasil untuk saya, saya hanya mendapatkan tanda kurung siku kosong, yaitu []
Soyf
Sayangnya, ini tidak mendukung Suffix :(
Anum Sheraz
Hebatnya adalah solusi ini bekerja bahkan dengan lebih dari 1000 objek
Mabyn
46

Saya merasa sudah lama dan boto3 memiliki beberapa cara berbeda untuk mencapai tujuan ini. Ini mengasumsikan Anda ingin menghapus tes "folder" dan semua objeknya Berikut adalah salah satu caranya:

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)

Ini harus membuat dua permintaan, satu untuk mengambil objek di folder, yang kedua untuk menghapus semua objek di folder tersebut.

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

Patrick
sumber
Sejauh ini, ini adalah solusi tercepat.
deepelement
2
Ini adalah solusi tercepat, tetapi perlu diingat bahwa list_objectstidak dapat mengembalikan lebih dari 1000 kunci sehingga Anda perlu menjalankan kode ini beberapa kali.
lamplave
4
Anda dapat menggunakan paginator jika Anda memiliki lebih dari 1k objek - lihat jawaban saya di bawah.
dmitrybelyakov
@deepelement, dan itu hanya bekerja di boto3, bukan boto
alpukat
1
Ini karya besar, dan Anda dapat menjalankannya dari lambda Python dengan menempatkan kode di atas dalam fungsi lambda_handler: import boto3; def lambda_handler(event, context): '''Code from above'''. Pastikan Anda memberikan izin Lambda Anda untuk menghapus dari S3 dan memperpanjang batas waktu.
Nadir Sidi
21

Anda dapat menggunakan bucket.delete_keys () dengan daftar kunci (dengan sejumlah besar kunci, saya menemukan bahwa urutan besarnya lebih cepat daripada menggunakan key.delete).

Sesuatu seperti ini:

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)
David Fooks
sumber
20

Sedikit perbaikan pada solusi Patrick. Seperti yang Anda ketahui, keduanya list_objects()dan delete_objects()memiliki batas objek 1000. Inilah sebabnya mengapa Anda harus membuat daftar halaman dan menghapus dalam potongan. Ini sangat universal dan Anda dapat memberikan Prefixuntuk paginator.paginate()untuk menghapus subdirektori / jalur

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)
dmitrybelyakov
sumber
2
Dan jika Anda ingin membatasi ke "direktori", gunakan Prefixkata kunci di paginator.paginate()Lihat semua opsi: boto3.readthedocs.io/en/latest/reference/services/…
Chad
1
dengan Prefixfilter yang disarankan oleh @Chad , saya harus menambahkan tanda if item is not Nonecentang sebelum menghapus (karena beberapa prefiks S3 saya tidak ada / tidak memiliki objek)
y2k-shubham
3

Jika pembuatan versi diaktifkan pada bucket S3:

s3 = boto3.resource('s3')
bucket = s3.Bucket('mybucket')
bucket.object_versions.filter(Prefix="myprefix/").delete()
Dan-Dev
sumber
Apakah ada cara untuk mencetak keluaran dari apa yang sedang dihapus? Saya ingin menghapus versi terlebih dahulu, lalu yang sekarang. ex bucket.objects.filter (Prefix = "myprefix /"). delete (); sekarang saya hanya melihat kursor yang berkedip dan saya tidak tahu apa yang terjadi.
DJ_Stuffy_K
1
Anda harus melakukan sesuatu seperti files_to_delete = bucket.object_versions.filter(Prefix="myprefix/")iterasi files_to_deletedan memanggil print () lalu delete () pada mereka.
Dan-Dev
1

Jika seseorang perlu memfilter berdasarkan konten objek seperti yang saya lakukan, berikut ini adalah cetak biru untuk logika Anda:

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})
Boris
sumber