78人参与 • 2026-10-11 • Python
在 python 中,删除文件和目录是最常见的文件系统操作之一。你可能已经熟练地使用 os.remove() 删除单个文件,用 os.rmdir() 清理空目录。然而,这两个看似简单的函数,却有着极为严格的规则:os.remove() 只能删文件,不能删目录;os.rmdir() 只能删空目录,一旦目录里还有任何东西,它就会拒绝执行。如果混淆了它们,你会在运行时收到 isadirectoryerror 或 oserror: directory not empty,而如果你错误地认为 os.rmdir() 可以像 rm -rf 那样递归删除,就会在需要清理目录树时束手无策。更危险的是,在不该删除的时候误删了文件,或在多进程环境中因竞态条件删错了目标。
今天,我们就来彻底解剖 os.remove() 和 os.rmdir() 的精确语义,揭示那些让你“删不掉”或“删错”的陷阱,并教你如何安全、可靠地管理文件和目录的删除操作。

import os
os.makedirs('my_folder')
os.remove('my_folder') # isadirectoryerror: [errno 21] is a directory
你以为 os.remove() 能删除任何东西,但它明确拒绝目录。删除目录需要不同的函数。
import os
os.makedirs('my_folder')
with open('my_folder/file.txt', 'w') as f:
f.write('data')
os.rmdir('my_folder') # oserror: [errno 39] directory not empty
os.rmdir() 只能删除空目录。如果目录里还有文件或子目录,它会抛出 oserror,并且不会删除任何内容。
os.makedirs('a/b/c')
os.rmdir('a') # oserror: directory not empty
很多人误以为 os.rmdir() 会像 rm -r 一样递归删除,但它的名字已经说明了:它只移除空目录。要递归删除,必须使用 shutil.rmtree()。
os.remove('not_exist.txt') # filenotfounderror
在清理脚本中,如果目标文件已经不存在,os.remove() 会直接崩溃。需要先检查或捕获异常。
import os
with open('data.txt', 'w') as f:
f.write('data')
os.remove('data.txt') # 在 windows 上会 permissionerror
在 windows 上,如果文件仍被打开,os.remove() 会失败。在 unix 上,文件会被立即从目录项中移除,但已打开的文件描述符仍然有效,直到关闭。这种平台差异容易导致跨平台 bug。
import os
os.symlink('/important/data.txt', 'link.txt')
os.remove('link.txt') # 删除的是链接本身,不是目标,这是正确的
但如果用 os.rmdir() 去删除指向目录的符号链接,在 unix 上它会删除链接,而不是目标目录。然而,如果符号链接指向一个空目录,某些操作可能会让人混淆。
import os
def cleanup(path):
if os.path.exists(path):
os.remove(path) # 在检查与删除之间,文件可能被其他进程重建
先检查再删除的“检查-使用”竞态,可能导致删除一个本不该删除的新文件。应直接尝试删除并捕获 filenotfounderror。
os.remove() 和 os.unlink() 在 unix 和 windows 上功能相同,os.unlink() 是更底层的 posix 名称。path 可以是字符串或路径类对象(如 pathlib.path)。isadirectoryerror(unix)或 permissionerror(windows)。filenotfounderror。oserror(directory not empty)。notadirectoryerror。filenotfounderror。os.rmdir() 会删除链接本身(而不是目标),这符合 posix 语义。但这一行为在不同平台可能不一致,应谨慎。shutil.rmtree(path) 递归删除整个目录树(包括非空目录)。它内部会遍历目录,对文件调用 os.unlink(),对子目录调用 os.rmdir()。因此,os.remove() 和 os.rmdir() 是 rmtree 的基石,但 rmtree 提供了更高级的便利和错误处理。
os.remove() 和 os.rmdir() 都不是幂等的:文件或目录不存在时会抛出异常。要实现幂等删除,需要捕获异常:
try:
os.remove(path)
except filenotfounderror:
pass
两者都接受 path-like 对象,包括 pathlib.path。
os.remove() 或 os.unlink()。os.rmdir()。shutil.rmtree()。把文件和目录搞混,是初学者最常见的错误。
这是最危险的误解之一。os.rmdir() 只删除空目录,非空会报错,绝不会递归。递归删除必须显式使用 shutil.rmtree()。
在清理脚本中,文件可能已经不存在。不捕获异常会导致脚本中断。
# 错误
os.remove('temp.txt')
# 正确
try:
os.remove('temp.txt')
except filenotfounderror:
pass
if os.path.exists(path):
os.remove(path)
这可能在检查后、删除前被其他进程删除,导致 filenotfounderror。更好的方式是直接删除并捕获异常。
os.remove('some_dir') # isadirectoryerror
应使用 os.rmdir() 或 shutil.rmtree()。
windows 不允许删除被打开的文件。如果文件被其他进程占用,os.remove() 会抛出 permissionerror。解决方案:确保文件已关闭,或使用 try/except 并重试。
os.remove('data/' + filename)
如果 filename 是 ../../important.txt,可能删除预期之外的文件。应对路径进行规范化,并校验其在允许的目录内。
if os.path.isdir(path):
os.rmdir(path) # 如果 path 是指向目录的符号链接,可能不是你想要的行为
os.path.isdir() 会跟随符号链接,返回 true。但 os.rmdir() 对符号链接的操作是删除链接本身(unix),而不是目标。如果不理解这一点,可能造成混淆。
import os
def safe_remove_file(path):
try:
os.remove(path)
except filenotfounderror:
pass # 文件已不存在,无需处理
except isadirectoryerror:
raise valueerror(f"{path} 是一个目录,请使用 rmdir 或 rmtree")
except permissionerror:
raise # 权限不足,需要调用者处理
import os
def safe_remove_empty_dir(path):
try:
os.rmdir(path)
except filenotfounderror:
pass
except oserror as e:
if e.errno == 39: # directory not empty
raise valueerror(f"{path} 不是空目录,请使用 shutil.rmtree")
raise
import shutil shutil.rmtree(path, ignore_errors=false) # 默认失败时抛异常 # 或忽略错误(不推荐) shutil.rmtree(path, ignore_errors=true)
更安全的做法是提供 onexc 回调处理只读文件:
import os
import stat
import shutil
def remove_readonly(func, path, exc):
os.chmod(path, stat.s_iwrite)
func(path)
shutil.rmtree(path, onexc=remove_readonly)
def remove_if_exists(path):
try:
os.remove(path)
except filenotfounderror:
pass
或者使用 pathlib:
from pathlib import path
p = path('data.txt')
p.unlink(missing_ok=true) # python 3.8+
missing_ok=true 使得文件不存在时不报错。
from pathlib import path
p = path('empty_dir')
try:
p.rmdir()
except filenotfounderror:
pass
path.rmdir() 也是只删空目录。
# 不要这样
if os.path.exists(path):
os.remove(path)
# 应该这样
try:
os.remove(path)
except filenotfounderror:
pass
from pathlib import path
file = path('data.txt')
file.unlink(missing_ok=true) # 删除文件
dir_path = path('empty_dir')
try:
dir_path.rmdir()
except filenotfounderror:
pass
import os
def safe_remove(base_dir, filename):
base = os.path.abspath(base_dir)
target = os.path.abspath(os.path.join(base, filename))
if not target.startswith(base + os.sep):
raise valueerror("路径越界")
os.remove(target)
打印异常的具体类型和错误码:oserror.errno 可以帮助区分不同原因。
在删除前记录文件状态:日志中记录 os.path.exists()、os.path.isdir()、os.path.islink() 的结果。
使用 pathlib 检查路径类型:
p = path(path) print(p.is_file(), p.is_dir(), p.is_symlink())
在测试中覆盖边界情况:文件不存在、目录非空、符号链接、只读文件等。
使用 try/except 而不是检查:避免竞态条件。
在 windows 上测试文件占用场景,确保正确处理 permissionerror。
os.remove() 或 os.unlink(),删除空目录用 os.rmdir(),删除非空目录用 shutil.rmtree()。filenotfounderror 实现幂等删除,或使用 path.unlink(missing_ok=true)。try/except 避免竞态。pathlib 提供更现代、更直观的 api。shutil.rmtree(),并处理好只读文件。os.remove() 和 os.rmdir() 是 python 文件系统操作的“精细手术刀”,它们各自负责不同的目标,有着严格的适用边界。把文件当目录删,或者试图用 rmdir 递归清理,都会让你在异常面前束手无策。理解了它们的分工,并在需要时升级到 shutil.rmtree() 或 pathlib 的现代 api,你就能在各种删除场景中游刃有余。从今天起,请对你的每一次删除操作都多一份谨慎:确认目标类型、处理不存在的情况、防范路径穿越,并记录操作日志。这样,你的文件清理将既干净利落,又安全可靠,再也不会出现“删不掉”或“删错了”的尴尬。
以上就是python使用os.remove()与os.rmdir()删除文件与目录操作详解的详细内容,更多关于python删除文件与目录的资料请关注代码网其它相关文章!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论