使用Python递归删除文件夹

337
我在删除空目录时遇到了问题。这是我的代码:
for dirpath, dirnames, filenames in os.walk(dir_to_search):
    # other codes

    try:
        os.rmdir(dirpath)
    except OSError as ex:
        print(ex)

参数dir_to_search是我传递工作所需的目录。该目录看起来像这样:
test/20/...
test/22/...
test/25/...
test/26/...

请注意,所有上述文件夹均为空。当我运行此脚本时,仅2025文件夹被删除!但是,尽管这些文件夹为空文件夹,2526文件夹并未被删除。

编辑:

我收到的异常是:

[Errno 39] Directory not empty: '/home/python-user/shell-scripts/s3logs/test'
[Errno 39] Directory not empty: '/home/python-user/shell-scripts/s3logs/test/2012'
[Errno 39] Directory not empty: '/home/python-user/shell-scripts/s3logs/test/2012/10'
[Errno 39] Directory not empty: '/home/python-user/shell-scripts/s3logs/test/2012/10/29'
[Errno 39] Directory not empty: '/home/python-user/shell-scripts/s3logs/test/2012/10/29/tmp'
[Errno 39] Directory not empty: '/home/python-user/shell-scripts/s3logs/test/2012/10/28'
[Errno 39] Directory not empty: '/home/python-user/shell-scripts/s3logs/test/2012/10/28/tmp'
[Errno 39] Directory not empty: '/home/python-user/shell-scripts/s3logs/test/2012/10/26'
[Errno 39] Directory not empty: '/home/python-user/shell-scripts/s3logs/test/2012/10/25'
[Errno 39] Directory not empty: '/home/python-user/shell-scripts/s3logs/test/2012/10/27'
[Errno 39] Directory not empty: '/home/python-user/shell-scripts/s3logs/test/2012/10/27/tmp'

我在哪里犯了错误?


1
你确定他们没有隐藏文件吗? - Jeff
是否打印了异常或回溯信息?如果是的话,将其添加到问题中会更有帮助。 - Ngure Nyaga
@Jeff:是的,我确定。实际上,在我的Ubuntu机器上,我尝试使用rmdir /path/to/25th/folder命令删除整个目录。这意味着该目录为空! - sriram
2
可能是重复的问题,与如何使用Python删除非空文件夹? 的问题和答案都相同。 - Trevor Boyd Smith
13个回答

694

尝试使用shutil.rmtree

import shutil
shutil.rmtree('/path/to/your/dir/')

8
rmtree是否删除整个目录?我猜它类似于 rm -Rf $DIR - sriram
16
注意,rmtree也会删除文件。如所问,问题是如何删除空目录。os.walk的文档提供了一个几乎完全符合此问题的示例代码:import os for root, dirs, files in os.walk(top, topdown=False): for name in dirs: os.rmdir(os.path.join(root, name)) - DaveSawyer
这个解决方案有问题吗?为什么需要更多的答案? :/ - Charlie Parker
@CharlieParker - 这个答案没有任何问题。其他答案的原因有时是因为人们可能不知道做某事的惯用方式,或者他们有特定的原因/用例不使用惯用方式,或者他们想出于某种原因强调不同的方法。如果你想深入了解,那么你应该开一个新问题。 - keithpjolley

44

这是我的纯净的pathlib递归目录删除器:

from pathlib import Path

def rmdir(directory):
    directory = Path(directory)
    for item in directory.iterdir():
        if item.is_dir():
            rmdir(item)
        else:
            item.unlink()
    directory.rmdir()

rmdir(Path("dir/"))

1
它应该比shutil更好,因此shutil是异步的。 - Olga Pshenichnikova
2
非常好,递归的一个实际例子也是一个额外的奖励。 - Nesha25
1
这是一个非常好的解决方案!在我的用例中,如果目录不存在,它不应该抛出异常,因此我还添加了一个 if not directory.exists() return 在迭代目录内容之前。 - dheinz
3
shutil.rmtree(path)有什么问题? - Charlie Parker

37

os.walk()的默认行为是从根部往叶子节点遍历。在os.walk()中设置 topdown=False可以从叶子节点向根部遍历。


5
shutil.rmtree(path)有什么问题? - Charlie Parker

16
尝试使用Python标准库中的shutil中的rmtree()

1
rmtree是否会删除整个目录?我猜它类似于rm -Rf $DIR - sriram
2
从文档中:删除整个目录树;路径必须指向一个目录(但不能是指向目录的符号链接)。如果 ignore_errors 为 true,则忽略由于删除失败而导致的错误;如果为 false 或省略,则通过调用由 onerror 指定的处理程序来处理这些错误,如果未指定,则会引发异常。 - microo8

7
最好使用绝对路径,并只导入rmtree函数。 from shutil import rmtree 由于这是一个大型软件包,上述代码将只导入所需的函数。
from shutil import rmtree
rmtree('directory-absolute-path')

6

针对下一个寻找MicroPython解决方案的人,这个解决方案完全基于操作系统(listdir、remove、rmdir)实现。它并不完整(尤其是在错误处理方面),也不花哨,但在大多数情况下都能够正常工作。

def deltree(target):
    print("deltree", target)
    for d in os.listdir(target):
        try:
            deltree(target + '/' + d)
        except OSError:
            os.remove(target + '/' + d)

    os.rmdir(target)

shutil.rmtree(path)有什么问题? - Charlie Parker

4

如果文件是只读的,Tomek给出的命令无法删除该文件。因此,可以使用-

import os, sys
import stat

def del_evenReadonly(action, name, exc):
    os.chmod(name, stat.S_IWRITE)
    os.remove(name)

if  os.path.exists("test/qt_env"):
    shutil.rmtree('test/qt_env',onerror=del_evenReadonly)

2
尝试使用自己的文件夹删除代码时,我收到了一个错误提示:NameError:name 'stat' is not defined。它是如何被定义的? - nnako
1
stat模块定义了常量和函数,用于解释os.stat()、os.fstat()和os.lstat()的结果。你可以尝试导入os和sys,以及从stat中导入所有内容(*)。 - Monir

2

如果您只想删除单个路径,例如:os.removedirs命令是最适合的工具。

os.removedirs("a/b/c/empty1/empty2/empty3")

将会删除 empty1/empty2/empty3,但保留 a/b/c(假设 c 中还有其他内容)。

    removedirs(name)
        removedirs(name)
        
        Super-rmdir; remove a leaf directory and all empty intermediate
        ones.  Works like rmdir except that, if the leaf directory is
        successfully removed, directories corresponding to rightmost path
        segments will be pruned away until either the whole path is
        consumed or an error occurs.  Errors during this latter phase are
        ignored -- they generally mean that a directory was not empty.

1
这是一个递归解决方案:

def clear_folder(dir):
    if os.path.exists(dir):
        for the_file in os.listdir(dir):
            file_path = os.path.join(dir, the_file)
            try:
                if os.path.isfile(file_path):
                    os.unlink(file_path)
                else:
                    clear_folder(file_path)
                    os.rmdir(file_path)
            except Exception as e:
                print(e)

1
这是另一个纯pathlib解决方案,但没有使用递归:
from pathlib import Path
from typing import Union

def del_empty_dirs(base: Union[Path, str]):
    base = Path(base)
    for p in sorted(base.glob('**/*'), reverse=True):
        if p.is_dir():
            p.chmod(0o666)
            p.rmdir()
        else:
            raise RuntimeError(f'{p.parent} is not empty!')
    base.rmdir()

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