shutil.rmtree() 是删除非空目录最直接方式,递归删除所有内容但不进回收站、不可逆,需用 onerror 处理权限错误并捕获 FileNotFoundError 等异常。

用 shutil.rmtree() 是最直接的方式
Python 标准库的 shutil.rmtree() 就是专为删除非空目录设计的,它会递归删除目标路径下所有文件、子目录及符号链接。不需要先清空再删,也不用自己写遍历逻辑。
但要注意:它不走回收站,删除不可逆;且对权限敏感,遇到只读文件或无写权限的子项会直接抛 PermissionError。
- 默认行为不忽略错误,出错就中断 —— 所以生产环境务必加异常处理
- Python 3.12+ 支持
onexc参数(已弃用),推荐用onerror回调处理权限问题 - Windows 下若目录中有正在被占用的文件(如日志被其他进程打开),会触发
WindowsError或OSError
处理权限拒绝的常见写法
典型场景是 Windows 上的只读文件,或 Linux 下 root 创建的子目录。直接调用 shutil.rmtree(path) 很可能失败。
安全做法是传入 onerror 回调,在报错时尝试修正权限再重试:
立即学习“Python免费学习笔记(深入)”;
import os
import stat
import shutil
<p>def _handle_remove<em>readonly(func, path, </em>):</p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/xiazai/skill8054" title="python-parallelization"><img
src="https://img.php.cn/upload/skill/000/000/081/179181013081932.jpg" alt="python-parallelization" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/xiazai/skill8054" title="python-parallelization">python-parallelization</a>
<p>将顺序 Python 代码转换为并行/并发实现,用于在需要并行化 Python 代码、提升性能时使用。</p>
</div>
<a href="/xiazai/skill8054" title="python-parallelization" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div><h1>先加写权限,再执行原操作</h1><pre class="brush:php;toolbar:false;">os.chmod(path, stat.S_IWRITE)
func(path)shutil.rmtree("/path/to/dir", onerror=_handle_remove_readonly)
-
onerror接收三个参数:func(失败的系统函数)、path(出问题的路径)、exc_info(异常信息) - 只对
os.remove和os.rmdir生效,不覆盖os.unlink等细节差异 - 不建议在回调里盲目
pass或忽略所有错误,否则可能静默跳过关键失败
需要确认存在性或避免误删?先检查再动手
shutil.rmtree() 对不存在的路径会抛 FileNotFoundError。如果你不确定路径是否存在,又不想让程序崩,有两种选择:
- 用
os.path.isdir(path)预检 —— 注意它不区分“不存在”和“存在但不是目录” - 更稳妥的是直接 try/except 捕获
FileNotFoundError和NotADirectoryError - 如果业务上允许“删掉就删掉,没有就不删”,捕获并忽略
FileNotFoundError即可
示例:
try:
shutil.rmtree(path)
except FileNotFoundError:
pass # 目录本来就没存在,算删除成功
except PermissionError as e:
print(f"权限不足,无法删除 {e.filename}")
替代方案:pathlib.Path.rmdir() 不适用
别被名字误导:pathlib.Path.rmdir() 只能删空目录,遇到任何子项都会报 OSError: Directory not empty。它和 os.rmdir() 行为一致,不是 rmtree 的面向对象封装。
想用 pathlib 安全删非空目录,仍得回退到 shutil.rmtree():
from pathlib import Path
import shutil
<p>p = Path("/tmp/mydir")
if p.is_dir():
shutil.rmtree(p)
另外注意:pathlib 本身不提供递归删除方法,也没有内置的权限修复逻辑 —— 这些都得靠你组合标准库来补足。
真正容易被忽略的点是:跨文件系统移动或删除时,某些 NFS 或容器挂载路径可能返回不一致的 stat 信息,导致 chmod 失效;这种情况下,onerror 回调里需要额外判断 exc_info[1].errno 做分支处理,不能只依赖通用只读修复逻辑。

















