shutil.rmtree()是Python标准库中唯一能直接递归删除非空目录的内置方案,它通过深度优先遍历彻底清除目录及其所有内容,但需配合onerror回调处理Windows只读文件等权限问题。

shutil.rmtree() 是唯一能直接删非空目录的内置方案
Python 标准库中,os.rmdir() 只能删空目录,而 shutil.rmtree() 是专为递归删除设计的函数。它不依赖 shell 命令,跨平台稳定,且默认行为就是“连目录带内容一起清掉”。但它的“安全”是相对的——没有回收站,也没有确认机制,一旦执行就不可逆。
常见错误现象:PermissionError: [WinError 5] 拒绝访问(Windows 下只读文件)、FileNotFoundError(路径不存在却仍调用)、或误删父目录(传入了相对路径如 ".." 而没做校验)。
- 务必先用
os.path.isdir()确认目标是目录,避免误删文件 - 对用户输入的路径,用
os.path.abspath()转成绝对路径再校验是否在允许范围内(比如限定在项目根目录下) - Windows 下只读文件会中断整个删除过程,需传入
onerror回调处理(见下一节)
处理 Windows 只读文件必须用 onerror 参数
Windows 的只读属性会让 shutil.rmtree() 在尝试删除时抛出 PermissionError 并中止,哪怕只是某个 .gitignore 文件被设为只读。这不是 bug,而是设计行为——它把控制权交给你决定怎么清理权限。
正确做法是提供一个 onerror 回调函数,在报错时先去掉只读位再重试:
import os
import shutil
<p>def remove<em>readonly(func, path, </em>):
os.chmod(path, stat.S_IWRITE)
func(path)</p><p>shutil.rmtree("my_dir", onerror=remove_readonly)
</p>
注意:onerror 的第三个参数是异常信息元组,通常不用;stat.S_IWRITE 需要 import stat;这个回调只对权限类错误生效,对路径不存在或磁盘满等其他错误无效。
想“安全”就得自己加防护层,shutil 不负责防手滑
shutil.rmtree() 本身没有任何交互、预览或干运行(dry-run)能力。所谓“安全删除”,全靠你在调用前加检查和确认逻辑。
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
- 用
pathlib.Path("target").rglob("*")预览将删哪些文件(注意:rglob("*")不包含目录自身,要手动加上) - 对敏感路径(如以
/home/、C:\Users\开头),直接拒绝执行 - 生产环境建议记录日志:
logging.info("Deleting %s (%d items)", path, len(list(Path(path).rglob("*")))) - 测试时可先用
shutil.move()把目录移到临时位置,确认无误再shutil.rmtree()
替代方案:tempfile.TemporaryDirectory 更适合临时清理
如果你删的是自己刚创建的临时目录(比如测试生成的缓存),别硬套 rmtree。用 tempfile.TemporaryDirectory() 上下文管理器更可靠:
from tempfile import TemporaryDirectory import os <p>with TemporaryDirectory() as tmpdir:</p><h1>所有操作在此目录内进行</h1><pre class="brush:php;toolbar:false;">os.makedirs(os.path.join(tmpdir, "sub")) # ……
退出 with 块后自动递归删除,且自带权限修复逻辑
它内部也调用 rmtree,但封装了 onerror 和异常保护,比裸调用更省心。不过它只适用于“我创建、我负责”的场景,不能用于清理外部路径。
真正容易被忽略的点是:所有路径校验和权限修复逻辑,都得在调用 rmtree 前完成——它不会帮你判断“该不该删”,只负责“怎么删”。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










