shutil.rmtree可递归删除非空目录,但遇windows只读文件会抛permissionerror;需传入三参数onerror回调,先用os.chmod(path, stat.s_iwrite)改权限,再调用func(path)重试。

shutil.rmtree 会直接删除非空目录,但默认不处理只读文件
调用 shutil.rmtree 确实能递归删掉整个目录树,包括子目录和所有文件,但它在遇到 Windows 下的只读文件(比如 .git 里的文件)时会抛出 PermissionError。这不是“删不了”,而是 Python 默认尊重系统权限位,不会主动改写文件属性。
常见错误现象:PermissionError: [WinError 5] 拒绝访问: 'xxx\xxx.py',尤其在删除含 .git 或 IDE 生成缓存的目录时高频出现。
- 解决方法是传入
onerror回调函数,在出错时先去掉只读属性再重试 - 不要用
os.system("rm -rf")或subprocess调 shell —— 跨平台性差,且绕过 Python 的异常控制流 - Python 3.12+ 提供了
ignore_errors=False参数(默认),但依然不自动修复权限,onerror仍是可靠解法
onerror 回调必须接受三个参数:func、path、exc_info
shutil.rmtree 要求 onerror 是一个三参数函数,否则会报 TypeError。它不是让你“捕获异常后忽略”,而是给你机会干预删除逻辑。
典型写法:
import os
import stat
import shutil
def remove_readonly(func, path, _):
"清除只读位并重试一次"
os.chmod(path, stat.S_IWRITE)
func(path)
shutil.rmtree("mydir", onerror=remove_readonly)
-
func是失败的系统调用(如os.remove或os.rmdir) -
path是出错的具体路径(文件或空目录) - 第三个参数是
sys.exc_info()元组,通常用不到,下划线占位即可 - 别漏掉
os.chmod(path, stat.S_IWRITE)—— 这步不做,重试仍会失败
shutil.rmtree 在 NFS 或符号链接挂载点上可能静默失败
如果目标路径位于 NFS、Docker volume 或通过 ln -s 挂载的目录中,shutil.rmtree 可能删掉符号链接本身,但不进入其指向的目标;或者因服务器端权限限制卡在某一层,既不报错也不继续。
调用 Cutout.Pro 视觉处理 API 进行背景移除、人像抠图和照片增强,支持文件上传与图片 URL 输入。
使用场景判断:
- 先用
os.path.islink(path)检查是否为符号链接 —— 若是,需决定是删链接还是删目标 - 对 NFS 路径,建议加超时控制:用
threading.Timer包裹调用,避免阻塞主线程 - Linux 下可配合
find . -xdev -delete验证是否真删干净(-xdev防跨文件系统误删)
替代方案:pathlib.Path.rmdir 不支持非空目录,别误用
有人看到 pathlib.Path.rmdir() 就想拿来删非空目录,结果触发 OSError: The directory is not empty。这是设计使然:rmdir() 对应系统 rmdir(2),仅支持空目录。
正确选择:
- 要删非空目录 → 坚持用
shutil.rmtree+onerror - 只删空目录 → 用
pathlib.Path.rmdir()更语义清晰,且自动处理路径对象 - 想保留父目录只清内容 → 用
shutil.rmtree(path / "*")不行(glob 不支持通配符递归),得手动遍历path.iterdir()再逐个删
最常被忽略的是:onerror 函数里改完权限后必须显式调用 func(path),否则就只是改了权限,没真正执行删除。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










