创建临时文件、日志或构建工件的脚本通常需要自行清理。您可能需要删除单个文件、匹配特定模式的所有文件或整个目录树。
Python 没有单一函数来完成所有这些操作。os、pathlib 和 shutil 模块各自覆盖该任务的不同部分。
本文介绍如何使用 os.remove()、pathlib.Path.unlink() 和 shutil.rmtree() 删除文件和目录,包括基于模式的删除和递归目录删除。
删除文件
在 Python 中,您可以使用 os.remove()、os.unlink()、pathlib.Path.unlink() 删除单个文件。
os 模块提供了一种与操作系统交互的可移植方式。
要使用 os.remove() 删除单个文件,请将文件路径作为参数传递:
import os
file_path = '/tmp/file.txt'
os.remove(file_path)os.remove() 和 os.unlink() 函数在语义上是相同的:
import os
file_path = '/tmp/file.txt'
os.unlink(file_path)如果指定的文件不存在,Python 会抛出 FileNotFoundError 异常。os.remove() 和 os.unlink() 只能删除文件,不能删除目录。如果给定的路径指向一个目录,Python 会抛出 OSError;具体的子类取决于操作系统。
删除文件需要包含该文件的目录具有写入和执行权限。否则,您将收到 PermissionError。
为避免删除文件时出错,您可以使用异常处理来捕获异常并发送适当的错误消息:
import os
file_path = '/tmp/file.txt'
try:
os.remove(file_path)
except OSError as e:
print("Error: %s: %s" % (file_path, e.strerror))pathlib 模块提供了用于处理文件系统路径的面向对象的接口。它在 Python 3.4 及以上版本中可用。
要使用 pathlib 模块删除文件,请创建一个指向该文件的 Path 对象,并在该对象上调用 unlink() 方法:
from pathlib import Path
file_path = Path('/tmp/file.txt')
try:
file_path.unlink()
except OSError as e:
print("Error: %s: %s" % (file_path, e.strerror))在 Python 3.8 及以上版本中,您可以传递 missing_ok=True 来抑制文件不存在时的 FileNotFoundError:
from pathlib import Path
Path('/tmp/file.txt').unlink(missing_ok=True)pathlib.Path.unlink()、os.remove() 和 os.unlink() 也可用于删除符号链接。
如果文件存在则删除文件
常见需求是仅在文件存在时删除它,如果不存在则不抛出错误。如果您使用的是 Python 3.8 或更新版本,Path.unlink(missing_ok=True) 是最简单的选项,如上所示。
对于 os.remove(),建议捕获 FileNotFoundError 而不是先进行检查。这避免了另一种进程在检查后但在 os.remove() 运行之前删除文件的竞争条件:
import os
file_path = '/tmp/file.txt'
try:
os.remove(file_path)
except FileNotFoundError:
pass您也可能看到使用 os.path.exists() 先检查路径的示例:
import os
file_path = '/tmp/file.txt'
if os.path.exists(file_path):
os.remove(file_path)这对于简单脚本来说是可以接受的,但它不如处理 FileNotFoundError 安全。它对于损坏的符号链接也返回 False;如果您需要检测并删除损坏的符号链接,请使用 os.path.lexists()。
按模式删除文件
您可以使用 glob 模块根据模式匹配多个文件。例如,要删除 /tmp 目录中的所有 .txt 文件,您可以使用类似以下内容:
import os
import glob
files = glob.glob('/tmp/*.txt')
for f in files:
try:
os.remove(f)
except OSError as e:
print("Error: %s: %s" % (f, e.strerror))要递归删除 /tmp 目录及其所有子目录中的所有 .txt 文件,请将 recursive=True 参数传递给 glob() 函数并使用 ** 模式:
import os
import glob
files = glob.glob('/tmp/**/*.txt', recursive=True)
for f in files:
try:
os.remove(f)
except OSError as e:
print("Error: %s: %s" % (f, e.strerror))pathlib 模块包含两个 glob 方法 glob() 和 rglob(),用于匹配目录中的路径。glob() 遵循您提供的相对模式,包括嵌套和递归模式。rglob() 在不需要 **/ 前缀的情况下递归搜索。以下示例删除 /tmp 目录顶层中的所有 .txt 文件:
from pathlib import Path
for f in Path('/tmp').glob('*.txt'):
try:
f.unlink()
except OSError as e:
print("Error: %s: %s" % (f, e.strerror))删除目录中的所有文件
有时您需要清空目录但保留目录本身。例如,您可能希望在脚本每次运行之前清除缓存或上传文件夹。
警告使用 unlink() 删除的文件不会进入回收站。先打印路径列表并在删除任何内容之前进行检查。
要查看目录中的条目,请使用 iterdir() 对其进行循环并打印每个路径:
from pathlib import Path
for f in Path('/tmp/data').iterdir():
print(f)iterdir() 方法返回目录中的每个条目,包括隐藏文件和子目录。以下代码删除文件和符号链接并保留子目录:
from pathlib import Path
for f in Path('/tmp/data').iterdir():
if f.is_file() or f.is_symlink():
f.unlink()is_file() 方法遵循符号链接,当链接目标缺失时返回 False。is_symlink() 检查可捕获这些损坏的链接。指向目录的符号链接作为链接删除,而它指向的目录不受影响。
要同时删除所有子目录中的文件,请将 iterdir() 替换为 rglob('*')。实际的目录保留在原处,而文件和符号链接被删除:
from pathlib import Path
for f in Path('/tmp/data').rglob('*'):
if f.is_file() or f.is_symlink():
f.unlink()您也可能看到使用 shutil.rmtree() 删除整个目录,然后使用 os.mkdir() 再次创建它的代码。它更短,但它也会删除子目录。新目录还会获得默认权限并属于运行脚本的用户,而不是原始所有者。
删除目录(文件夹)
在 Python 中,您可以使用 os.rmdir() 和 pathlib.Path.rmdir() 删除空目录,并使用 shutil.rmtree() 删除非空目录。
以下示例显示如何删除空目录:
import os
dir_path = '/tmp/img'
try:
os.rmdir(dir_path)
except OSError as e:
print("Error: %s: %s" % (dir_path, e.strerror))或者,您可以使用 pathlib 模块删除目录:
from pathlib import Path
dir_path = Path('/tmp/img')
try:
dir_path.rmdir()
except OSError as e:
print("Error: %s: %s" % (dir_path, e.strerror))shutil 模块允许您对文件和目录执行多种高级操作。
警告请小心使用 shutil.rmtree(),因为它会递归删除目录及其下的所有内容。运行之前仔细检查路径,特别是当路径来自变量或用户输入时。
使用 shutil.rmtree() 函数可以删除给定目录及其内容:
import shutil
dir_path = '/tmp/img'
try:
shutil.rmtree(dir_path)
except OSError as e:
print("Error: %s: %s" % (dir_path, e.strerror))传递给 shutil.rmtree() 的参数不能是目录的符号链接。
要静默忽略删除期间的任何错误,请传递 ignore_errors=True:
import shutil
shutil.rmtree('/tmp/img', ignore_errors=True)pathlib 模块没有用于删除非空目录的方法。Path.rmdir() 仅适用于空目录。要删除目录树,请将 Path 对象传递给 shutil.rmtree():
import shutil
from pathlib import Path
shutil.rmtree(Path('/tmp/img'))快速参考
对于可打印的快速参考,请参阅 Python 速查表。
| 任务 | 函数 |
|---|---|
| 删除文件 | os.remove(path) 或 Path(path).unlink() |
| 删除文件(如果不存在则不报错) | Path(path).unlink(missing_ok=True) |
| 删除符号链接 | os.remove(path) 或 Path(path).unlink() |
| 删除空目录 | os.rmdir(path) 或 Path(path).rmdir() |
| 删除目录及其内容 | shutil.rmtree(path) |
| 删除目录并忽略错误 | shutil.rmtree(path, ignore_errors=True) |
| 按模式删除文件 | glob.glob(pattern) + os.remove() |
| 递归按模式删除文件 | glob.glob('**/*.ext', recursive=True) + os.remove() |
| 使用 pathlib glob 删除文件 | Path(dir).glob('*.ext') + .unlink() |
| 递归使用 pathlib 删除文件 | Path(dir).rglob('*.ext') + .unlink() |
| 删除目录中的所有文件 | Path(dir).iterdir() + 对文件调用 .unlink() |
常见问题解答
os.remove() 和 os.unlink() 有什么区别?
它们在语义上是完全相同的。unlink 是该操作在 Unix 系统中的传统名称。两者都用于删除单个文件,如果路径不存在则会抛出 FileNotFoundError。
如何删除目录及其所有内容?
使用 shutil.rmtree(path)。若要抑制错误,请传递 ignore_errors=True。请注意,os.rmdir() 仅适用于空目录。
我可以使用 pathlib 删除匹配特定模式的文件吗?
可以。使用 Path(directory).glob('*.txt') 来匹配文件,并对每个结果调用 .unlink()。对于递归匹配,请使用 .rglob('*.txt')。