亚马逊S3 boto - 如何删除文件夹?

146

我在S3中创建了一个名为“test”的文件夹,并将“test_1.jpg”和“test_2.jpg”推送到了“test”文件夹中。

我该如何使用Boto删除“test”文件夹?

8个回答

345

这是2018年(即将到来的2019年)版本:

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

8
有人可能会发现有用的是,bucket.objects.all().delete() 可以清空整个存储桶而不删除它,无论存储对象的数量有多少(即不受1000个项目限制的影响)。请参阅:https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Bucket.objects - fabiog1901
3
嗨 Raz,这对我没用,我只是得到了空方括号,即 []。 - Whitey Winn
1
很遗憾,这不支持后缀 :( - Anum Sheraz
5
非常好的是,即使有超过1000个对象,这个解决方案仍然有效。 - Mabyn
1
@raz 如果可能的话,您能否更新答案以反映/打印正在被删除的内容,并在令牌过期时退出程序?现在它运行良好,但是没有办法知道正在删除什么以及发生了什么,因为我只得到一个闪烁的光标。 - DJ_Stuffy_K
显示剩余4条评论

71

在S3中并没有文件夹。相反,键形成一个平面的命名空间。然而,在名称中包含斜杠的键在某些程序中会显示特殊,包括AWS控制台(例如请参见Amazon S3 boto-如何创建文件夹?)。

相对于删除“目录”,你可以(也必须)按前缀列出文件并进行删除。实质上:

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

然而,此页面上其他完成的答案采用了更有效的方法。


请注意,前缀只是使用虚拟字符串搜索来查找的。如果前缀是your/directory,即没有附加尾部斜杠,则该程序也会愉快地删除your/directory-that-you-wanted-to-remove-is-definitely-not-t‌​his-one

有关更多信息,请参见S3 boto list keys sometimes returns directory key。


1
如何删除目录?如果该目录中的所有文件都被删除,该目录是否会自动删除? - wade huang
@wadehuang - 你能分享一下删除文件夹的代码吗? - letsc
如何在Python中删除S3文件夹中两天前的文件。我有这个S3 - bucket / 1 / backups /(10个文件),需要删除所有两天前的文件。 - 艾瑪艾瑪艾瑪

59

我感觉有一段时间了,boto3有几种不同的方法可以实现这个目标。假设你想要删除test文件夹及其所有对象。这是一种方法:

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)

这应该会发起两个请求,一个用于获取文件夹中的对象,第二个用于删除该文件夹中的所有对象。

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


3
这是最快的解决方案,但要注意 list_objects 无法返回超过1000个键,因此您需要多次运行此代码。 - lampslave
4
如果您有超过1000个对象,您可以使用分页器 - 请参见下面的回答。 - dmitrybelyakov
@deepelement,它只在boto3中有效,而不是boto。 - avocado
2
这个很好用,你可以通过将上面的代码放在lambda_handler函数中,在Python lambda中运行它:import boto3; def lambda_handler(event, context): '''Code from above'''。确保你的Lambda有权限从S3中删除并延长超时时间。 - Nadir Sidi

31

对Patrick的解决方案稍作改进。你可能知道,list_objects()delete_objects()都有1000个对象的限制。这就是为什么你需要分页列出和删除块。这是相当普遍的,你可以给paginator.paginate()提供Prefix来删除子目录/路径。

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
如果你想限制到一个“目录”,可以在 paginator.paginate() 中使用 Prefix 关键字。查看所有选项:http://boto3.readthedocs.io/en/latest/reference/services/s3.html#S3.Paginator.ListObjectsV2.paginate - Chad
3
@Chad 建议使用 Prefix 过滤器后,我需要在删除之前添加一个 if item is not None 检查(因为我的一些 S3 前缀不存在/没有对象)。 - y2k-shubham
@dmitraybelyakov,当我运行上面的代码时,我在以下行上得到了Typeerror:'NoneType'对象不可脚本化delete_us['Objects'].append(dict(key=item['Key']))。您知道为什么会这样吗? - Aaron
@Aaron,也许有些事情已经改变了,但请尝试y2k-shubham上面的建议。 - dmitrybelyakov
前缀:工作得很好! - Rajnish kumar

24
你可以使用bucket.delete_keys()函数并提供一个键列表(在具有大量键的情况下,我发现这比使用key.delete快一个数量级)。
类似这样:
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)

9
如果S3存储桶启用了版本控制:
s3 = boto3.resource('s3')
bucket = s3.Bucket('mybucket')
bucket.object_versions.filter(Prefix="myprefix/").delete()

有没有办法打印出正在删除的输出?我想先删除版本,然后再删除当前版本。例如 bucket.objects.filter(Prefix="myprefix/").delete();现在我只看到一个闪烁的光标,不知道正在发生什么。 - DJ_Stuffy_K
1
你需要做的是像这样:files_to_delete = bucket.object_versions.filter(Prefix="myprefix/"),然后遍历files_to_delete并在其上调用print()和delete()。 - Dan-Dev

3
如果需要像我一样按对象内容进行过滤,则以下是您逻辑的蓝图:
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})

0

#使用boto3删除S3文件夹内的文件#

def delete_from_minio():
    """
    This function is used to delete files or folder inside the another Folder
    """
    try:
        logger.info("Deleting from minio")
        aws_access_key_id='Your_aws_acess_key'
        aws_secret_access_key = 'Your_aws_Secret_key'
        host = 'your_aws_endpoint'
        s3 = boto3.resource('s3', aws_access_key_id=aws_access_key_id,
                            aws_secret_access_key=aws_secret_access_key ,
                            config=boto3.session.Config(signature_version='your_version'),
                            region_name="your_region",
                            endpoint_url=host ,
                            verify=False)
        bucket = s3.Bucket('Your_bucket_name')
        for obj in bucket.objects.filter(Prefix='Directory/Sub_Directory'):
            s3.Object(bucket.name, obj.key).delete()
    except Exception as e:
        print(f"Error Occurred while deleting from the S3,{str(e)}")

希望这有帮助 :)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接