PathLib 递归删除目录?

155

在PathLib模块中,有没有一种方法可以删除目录及其内容?使用path.unlink()只能删除文件,而使用path.rmdir()则需要目录为空。难道没有一种方法可以在一个函数调用中完成吗?

7个回答

189

正如您所知,唯一的两个Path方法用于删除文件/目录是.unlink().rmdir(),但都不是您想要的。

Pathlib是一个跨不同操作系统提供面向对象路径的模块,它不旨在拥有许多不同的方法。

该库的目标是提供一个简单的类层次结构来处理文件系统路径和用户对它们进行的常见操作。

像递归地删除目录这样的“不常见”的文件系统更改存储在不同的模块中。如果要递归地删除目录,则应使用shutil模块。(它也可以与Path实例一起工作!)

import shutil
import pathlib
import os  # for checking results

print(os.listdir())
# ["a_directory", "foo.py", ...]

path = pathlib.Path("a_directory")

shutil.rmtree(path)
print(os.listdir())
# ["foo.py", ...]

4
仅供参考,可以这样做- https://dev59.com/mGcs5IYBdhLWcg3wHwXU#49782093。 - El Ruso
157
为什么pathlib.Path没有递归版本,因为所需的一切都已经存在。我真的希望使用os.path、os.mkdir、shutil等会在pathlib中结束,这样就不那么困惑了。 - Sebastian Werk
4
@SebastianWerk PR! PR! PR! -- 虽然它已经在stdlibrary中,但很遗憾要等一段时间才能发布,并且需要花费大量的努力才能实现。我分享你的情感。 - SwimBikeRun
1
如果pth是一个Path对象,使用pth.rmdir()有什么问题,相比于你的答案? - Charlie Parker
6
path.rmdir() 只会在目录为空的情况下删除该目录。 - Rahul A Ranger
显示剩余2条评论

29
这是一个纯粹的pathlib实现:
from pathlib import Path


def rm_tree(pth):
    pth = Path(pth)
    for child in pth.glob('*'):
        if child.is_file():
            child.unlink()
        else:
            rm_tree(child)
    pth.rmdir()

5
这将会删除符号链接目录的内容,我想是吗? - user2846495
2
shutil.rmtree 的不安全版本执行类似的操作(来源),但在符号链接目录的情况下会引发 OSError("Cannot call rmtree on a symbolic link") - djvg
与您的答案相比,使用shutil.rmtree(path)有什么问题? - Charlie Parker

16
否则,如果你只想使用pathlib,你可以尝试这个:
from pathlib import Path


def rm_tree(pth: Path):
    for child in pth.iterdir():
        if child.is_file():
            child.unlink()
        else:
            rm_tree(child)
    pth.rmdir()

rm_tree(your_path)

在迭代目录时改变该目录是否安全?在开始迭代之前,可能需要将iterdir()的完整结果提取到列表中。 - Roger Dahl
递归函数将继续删除文件(child.unlink()),直到目录为空。一旦为空,目录将被删除(pth.rmdir())。 - Rami

8
简单而有效:
def rmtree(f: Path):
    if f.is_file():
        f.unlink()
    else:
        for child in f.iterdir():
            rmtree(child)
        f.rmdir()

7

你可以使用pathlib3x - 它提供了最新的(在撰写此答案时是Python 3.10.a0)Python pathlib的后移版本,适用于Python 3.6或更高版本,并提供一些额外的函数,如rmtree

>>> python -m pip install pathlib3x

>>> import pathlib3x as pathlib

>>> my_path = pathlib.Path('c:/tmp/some_directory')
>>> my_path.rmtree(ignore_errors=True)


你可以在GitHubPyPI上找到它。


免责声明:我是pathlib3x库的作者。


5
def rm_rf(basedir):
    if isinstance(basedir,str): basedir = pathlib.Path(basedir)
    if not basedir.is_dir(): return
    for p in reversed(list(basedir.rglob("*"))):
        if p.is_file(): p.unlink()
        elif p.is_dir(): p.rmdir()
    basedir.rmdir()

这似乎不能删除basedir下的非空子目录?@maf88提供的递归答案看起来更好。 - Thomas Browne

5
如果您不介意使用第三方库,可以尝试使用 path。 它的API与pathlib.Path类似,但提供了一些额外的方法,包括Path.rmtree()来递归删除目录树。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接