You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何递归删除Amazon S3指定子文件夹?

解决S3递归删除指定子文件夹的问题

我明白你现在的困扰——本来只想删bucket/do-not-delete-folder/delete-this-folder-recursively下的内容,结果要么误删了上层文件夹,要么碰到权限报错。我来帮你拆解问题,再给你一个靠谱的实现方案。

先分析你遇到的两个问题

1. 第一个函数误删上层文件夹

S3是扁平存储,所谓的“文件夹”只是前缀的一部分。你传入的前缀是do-not-delete-folder/delete-this-folder/,但如果函数里的前缀匹配逻辑有问题(比如没正确处理结尾的斜杠,或者在拼接前缀时出错),就可能会匹配到do-not-delete-folder/开头的所有对象,导致误删。比如如果函数里不小心把前缀写成了do-not-delete-folder/(少了后面的部分),或者用了不带结尾斜杠的前缀,S3会匹配所有以该字符串开头的对象,包括上层的内容。

2. 第二个函数的Access Denied问题

同一Lambda同一账号却报错,大概率是权限策略的资源范围不对,或者函数里的操作试图访问超出权限的资源。比如如果你的权限策略只给了delete-this-folder/下的删除权限,但函数里在列对象时需要访问整个bucket的list权限,或者不小心访问了其他路径的资源,就会触发拒绝。另外,如果存储桶开启了版本控制,而你的权限里没有s3:DeleteObjectVersion权限,也会报错。

正确的递归删除实现(Python + Boto3)

下面这个函数会严格限定只删除指定前缀下的所有对象(包括嵌套子“文件夹”对应的零字节对象),不会碰上层内容。如果你的存储桶开启了版本控制,也会一并处理所有版本和删除标记:

import boto3

def delete_s3_prefix_recursively(bucket_name, prefix):
    # 确保前缀以斜杠结尾,避免匹配到类似delete-this-folder123的前缀
    if not prefix.endswith('/'):
        prefix += '/'
    
    s3 = boto3.client('s3')
    paginator = s3.get_paginator('list_objects_v2')
    
    # 分页列出所有指定前缀下的对象
    page_iterator = paginator.paginate(
        Bucket=bucket_name,
        Prefix=prefix,
        PaginatorConfig={'PageSize': 1000}
    )
    
    # 批量删除对象,每次最多1000个
    for page in page_iterator:
        if 'Contents' not in page:
            continue
        
        objects_to_delete = [{'Key': obj['Key']} for obj in page['Contents']]
        
        # 如果存储桶开启了版本控制,取消下面注释处理版本和删除标记
        # if 'Versions' in page:
        #     objects_to_delete = [{'Key': obj['Key'], 'VersionId': obj['VersionId']} for obj in page['Versions']]
        #     if 'DeleteMarkers' in page:
        #         objects_to_delete.extend([{'Key': obj['Key'], 'VersionId': obj['VersionId']} for obj in page['DeleteMarkers']])
        
        response = s3.delete_objects(
            Bucket=bucket_name,
            Delete={'Objects': objects_to_delete}
        )
        
        # 可选:打印删除结果用于排查
        if 'Deleted' in response:
            print(f"Deleted {len(response['Deleted'])} objects")
        if 'Errors' in response:
            print(f"Errors deleting objects: {response['Errors']}")

# 调用示例:精准删除目标路径下的所有内容
delete_s3_prefix_recursively('my-bucket', 'do-not-delete-folder/delete-this-folder-recursively')

关键注意事项

  1. 前缀结尾的斜杠:一定要确保前缀以/结尾,比如do-not-delete-folder/delete-this-folder-recursively/,这样S3只会匹配以这个完整前缀开头的对象,不会误匹配类似do-not-delete-folder/delete-this-folder-recursively-extra的路径。
  2. 权限策略配置:给Lambda的执行角色添加以下权限,确保只允许访问目标路径:
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": "s3:ListBucket",
                "Resource": "arn:aws:s3:::my-bucket",
                "Condition": {
                    "StringLike": {
                        "s3:prefix": "do-not-delete-folder/delete-this-folder-recursively/*"
                    }
                }
            },
            {
                "Effect": "Allow",
                "Action": [
                    "s3:DeleteObject",
                    "s3:DeleteObjectVersion"  // 存储桶开启版本控制时需要此权限
                ],
                "Resource": "arn:aws:s3:::my-bucket/do-not-delete-folder/delete-this-folder-recursively/*"
            }
        ]
    }
    
  3. 版本控制处理:如果你的存储桶开启了版本控制,记得取消代码中对应部分的注释,否则即使删除了当前版本,旧版本依然会留在存储桶里。

验证方法

在正式运行前,可以先把delete_objects换成print,打印所有要删除的对象Key,确认没有包含do-not-delete-folder/下的其他内容,再执行删除操作。

内容的提问来源于stack exchange,提问作者bhuvanrk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:33:18