如何删除/删除不为空的文件夹?


846

尝试删除不为空的文件夹时,出现“访问被拒绝”错误。我尝试使用以下命令:os.remove("/folder_name")

删除/删除不为空的文件夹/目录的最有效方法是什么?


32
还要注意,即使目录为空,os.remove也会再次失败,因为正确的功能是os.rmdir。
tzot

Answers:


1345
import shutil

shutil.rmtree('/folder_name')

标准库参考:shutil.rmtree

根据设计,rmtree在包含只读文件的文件夹树上失败。如果要删除该文件夹而不管它是否包含只读文件,请使用

shutil.rmtree('/folder_name', ignore_errors=True)

73
需要注意的是rmtree,如果有只读文件会失败:stackoverflow.com/questions/2656322/...
斯里达尔Ratnakumar

9
这对我不起作用:追溯(最近一次通话是最近的):文件<foo>中的“ foo.py”,第31行,shutil.rmtree(thistestdir)文件“ /usr/lib/python2.6/shutil.py” ”,在rmtree onerror(os.rmdir,path,sys.exc_info())文件中的第225行,在rmtree os.rmdir(path)OSError中的“ /usr/lib/python2.6/shutil.py”文件,第223行[错误90]目录非空:“/路径/到/ rmtree”
克莱顿休斯

4
Clayton:很有可能在rmtree忙于删除内容的同时添加了一个文件,“ rm -rf”同样会失败。
DDAA

13
有人知道为什么os包中没有此功能吗?好像os.rmdir很没用。为什么以这种方式实现有什么好的论点?
马尔科姆

21
@Malcolm该软件包是OS功能的包装。在POSIX系统上,如果目录不为空,则rmdir将失败。在这方面,UbuntuWindows是POSIX兼容的流行示例。
伊恩·塞缪尔·麦克莱恩

138

Python文档os.walk()

# Delete everything reachable from the directory named in 'top',
# assuming there are no symbolic links.
# CAUTION:  This is dangerous!  For example, if top == '/', it
# could delete all your disk files.
import os
for root, dirs, files in os.walk(top, topdown=False):
    for name in files:
        os.remove(os.path.join(root, name))
    for name in dirs:
        os.rmdir(os.path.join(root, name))

1
好吧,也许我错了调情。但是我可以,现在我认为是正确的。
ddaa

3
@ddaa:虽然使用shutil绝对是最简单的方法,但是此解决方案肯定没有任何不妥协之处。我不会赞成这个答案,但是这次我只是想取消你的反对意见:)
杰里米·坎特雷尔

7
代码本身是pythonic。在实际程序中使用它而不是shutil.rmtree会显得有些不合逻辑:这将忽略“一种显而易见的方法”。无论如何,这是语义,删除了downmod。
ddaa

2
@ddaa是否要记录每个已删除的文件或目录是非Python的?我不确定该如何使用shutil.rmtree?
乔纳森·科玛

4
@ddaa令人深思,即夸张。我知道我在做什么 我只是以为您可能会想提供“ shutil.rmtree”可能不是正确的“合适方法”的原因,从而重新考虑“显而易见的方法”。
乔纳森·科玛

112
import shutil
shutil.rmtree(dest, ignore_errors=True)

1
这是正确的答案。在我的系统中,即使我将特定文件夹中的所有内容都设置为可读写,但是在尝试删除时仍会出现错误。ignore_errors=True解决了问题。
Aventinus

3
在我的答案中,该onerror参数代替ignore_errors。这样,只读文件将被删除而不是被忽略。
戴夫·钱德勒

是的,这不会在出错时删除文件。因此,基本上整个rmtree()方法都将被忽略。
Juha Untinen

1
这应该是对6年前接受的答案的小修改,而不是新的答案。我现在就做。
让·弗朗索瓦·科贝特

22

从python 3.4您可以使用:

import pathlib

def delete_folder(pth) :
    for sub in pth.iterdir() :
        if sub.is_dir() :
            delete_folder(sub)
        else :
            sub.unlink()
    pth.rmdir() # if you just want to delete dir content, remove this line

这里pth是一个pathlib.Path实例。不错,但可能不是最快的。


10

来自docs.python.org

本示例说明如何在Windows上删除目录树,其中某些文件的只读位已设置。它使用onerror回调清除只读位并重新尝试删除。任何后续故障都将传播。

import os, stat
import shutil

def remove_readonly(func, path, _):
    "Clear the readonly bit and reattempt the removal"
    os.chmod(path, stat.S_IWRITE)
    func(path)

shutil.rmtree(directory, onerror=remove_readonly)

7
import os
import stat
import shutil

def errorRemoveReadonly(func, path, exc):
    excvalue = exc[1]
    if func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES:
        # change the file to be readable,writable,executable: 0777
        os.chmod(path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)  
        # retry
        func(path)
    else:
        # raiseenter code here

shutil.rmtree(path, ignore_errors=False, onerror=errorRemoveReadonly) 

如果设置了ignore_errors,错误将被忽略;否则,如果设置了onerror,则将使用参数(函数,路径,exc_info)来处理错误,其中func为os.listdir,os.remove或os.rmdir;path是导致该函数失败的参数。而exc_info是sys.exc_info()返回的元组。如果ignore_errors为false并且onerror为None,则会引发异常。在此处输入代码


根据文档onerror引发的异常不会被捕获,因此我不确定您在这里引发代码的含义。
kmarsh

-1。与Dave Chandler的答案相比,这似乎过于复杂。另外,如果我们要删除只读文件,则无需使文件可执行。
idbrii

7

根据kkubasik的回答,删除之前检查文件夹是否存在,更可靠

import shutil
def remove_folder(path):
    # check if folder exists
    if os.path.exists(path):
         # remove if exists
         shutil.rmtree(path)
    else:
         # throw your exception to handle this special scenario
         raise XXError("your exception") 
remove_folder("/folder_name")

6
这引入了可能的比赛条件
Corey Goldberg

1
根据最Python的路到删除-一个文件-这五月-不存在,这是最好try去除和手柄except比电话exists()第一
TT--

6

如果您确定要删除整个目录树,并且不再对目录内容感兴趣,那么爬网整个目录树是愚蠢的……只需从python调用本机OS命令即可。它将更快,更有效且内存消耗更少。

RMDIR c:\blah /s /q 

或* nix

rm -rf /home/whatever 

在python中,代码看起来像..

import sys
import os

mswindows = (sys.platform == "win32")

def getstatusoutput(cmd):
    """Return (status, output) of executing cmd in a shell."""
    if not mswindows:
        return commands.getstatusoutput(cmd)
    pipe = os.popen(cmd + ' 2>&1', 'r')
    text = pipe.read()
    sts = pipe.close()
    if sts is None: sts = 0
    if text[-1:] == '\n': text = text[:-1]
    return sts, text


def deleteDir(path):
    """deletes the path entirely"""
    if mswindows: 
        cmd = "RMDIR "+ path +" /s /q"
    else:
        cmd = "rm -rf "+path
    result = getstatusoutput(cmd)
    if(result[0]!=0):
        raise RuntimeError(result[1])

33
-1。使用的全部目的shutil.rmdir是使您与操作系统类型隔离。
mtrw

3
我理解这个概念,但是当一个人充分意识到他要完全删除该文件夹的事实时,抓取整个文件树的意义何在?shutil.rmdir专门调用os.listdir(),os.path.islink()等。一些并非真正需要的检查,因为所有需要的是断开文件系统节点的链接。除了某些生成系统(例如用于MSAuto / WinCE开发的MSWindows)之外,shtuil.rmdir几乎总是会失败,因为基于MSAuto批处理的开发会在退出失败时锁定一些奇怪的生成文件,并且只有rmdir / S / Q或重新启动才有助于清除他们。
PM

2
是的,只是rm更接近内核,使用更少的时间,内存和cpu .....正如我说的,我之所以使用此方法是因为MSAuto批处理生成脚本留下了锁...
PM

3
是的,但是使用shutil使代码跨平台并抽象出平台细节。
xshoppyx

2
我不认为这个答案应该低于1,因为它为读者可能感兴趣的某些情况下的解决方案提供了很好的参考。我喜欢按顺序排列发布多个方法。因此,即使我不需要使用它,我现在也知道它可以完成以及如何完成。
kmcguire 2014年

5

只需一些python 3.5选项即可完成上述答案。(我很想在这里找到他们)。

import os
import shutil
from send2trash import send2trash # (shutil delete permanently)

删除文件夹(如果为空)

root = r"C:\Users\Me\Desktop\test"   
for dir, subdirs, files in os.walk(root):   
    if subdirs == [] and files == []:
           send2trash(dir)
           print(dir, ": folder removed")

如果包含此文件的文件夹也删除

    elif subdirs == [] and len(files) == 1: # if contains no sub folder and only 1 file 
        if files[0]== "desktop.ini" or:  
            send2trash(dir)
            print(dir, ": folder removed")
        else:
            print(dir)

如果仅包含.srt或.txt文件,则删除文件夹

    elif subdirs == []: #if dir doesn’t contains subdirectory
        ext = (".srt", ".txt")
        contains_other_ext=0
        for file in files:
            if not file.endswith(ext):  
                contains_other_ext=True
        if contains_other_ext== 0:
                send2trash(dir)
                print(dir, ": dir deleted")

删除小于400kb的文件夹:

def get_tree_size(path):
    """Return total size of files in given path and subdirs."""
    total = 0
    for entry in os.scandir(path):
        if entry.is_dir(follow_symlinks=False):
            total += get_tree_size(entry.path)
        else:
            total += entry.stat(follow_symlinks=False).st_size
    return total


for dir, subdirs, files in os.walk(root):   
    If get_tree_size(dir) < 400000:  # ≈ 400kb
        send2trash(dir)
    print(dir, "dir deleted")

4
请修正缩进和代码if files[0]== "desktop.ini" or:
Mr_and_Mrs_D

5

我想添加“纯路径库”方法:

from pathlib import Path
from typing import Union

def del_dir(target: Union[Path, str], only_if_empty: bool = False):
    target = Path(target).expanduser()
    assert target.is_dir()
    for p in sorted(target.glob('**/*'), reverse=True):
        if not p.exists():
            continue
        p.chmod(0o666)
        if p.is_dir():
            p.rmdir()
        else:
            if only_if_empty:
                raise RuntimeError(f'{p.parent} is not empty!')
            p.unlink()
    target.rmdir()

这取决于Path可排序的事实,较长的路径总是会在较短的路径之后排序,就像str。因此,目录将位于文件之前。如果我们反转排序,那么文件将位于它们各自的容器之前,因此我们可以简单地一遍一遍地取消链接/ rmdir文件。

优点:

  • 它不依赖于外部二进制文件:所有内容都使用Python的电池模块(Python> = 3.6)
  • 快速且内存高效:无需递归堆栈,无需启动子进程
  • 它是跨平台的(至少,这就是pathlibPython 3.6 中的承诺;上述所有操作都说不能在Windows上运行)
  • 如果需要,可以进行非常精细的日志记录,例如,记录每次删除的发生。

您还可以提供一个使用示例吗?del_dir(Path())?谢谢
lcapra

@lcapra只需用要删除的目录作为第一个arg来调用它即可。
pepoluan

3
def deleteDir(dirPath):
    deleteFiles = []
    deleteDirs = []
    for root, dirs, files in os.walk(dirPath):
        for f in files:
            deleteFiles.append(os.path.join(root, f))
        for d in dirs:
            deleteDirs.append(os.path.join(root, d))
    for f in deleteFiles:
        os.remove(f)
    for d in deleteDirs:
        os.rmdir(d)
    os.rmdir(dirPath)

非常适合制作脚本,在将文件盲目删除之前将其放在quarenteen中。
racribeiro

3

如果您不想使用该shutil模块,则可以使用该os模块。

from os import listdir, rmdir, remove
for i in listdir(directoryToRemove):
    os.remove(os.path.join(directoryToRemove, i))
rmdir(directoryToRemove) # Now the directory is empty of files

2
os.remove无法删除目录,因此OsError如果directoryToRemove包含子目录,则会引起此问题。
同名的

#pronetoraceconditions
kapad

3

十年后,使用Python 3.7和Linux仍然有不同的方法:

import subprocess
from pathlib import Path

#using pathlib.Path
path = Path('/path/to/your/dir')
subprocess.run(["rm", "-rf", str(path)])

#using strings
path = "/path/to/your/dir"
subprocess.run(["rm", "-rf", path])

本质上,它是使用Python的子进程模块来运行bash脚本,$ rm -rf '/path/to/your/dir就像使用终端来完成相同的任务一样。它不是完全Python,但是可以完成。

我包含该pathlib.Path示例的原因是因为根据我的经验,在处理许多变化的路径时,它非常有用。导入pathlib.Path模块并将最终结果转换为字符串的额外步骤通常对我来说是较低的开发时间成本。如果Path.rmdir()带有arg选项来显式处理非空dirs ,将很方便。


我还改用了这种方法,因为我遇到了rmtree和这类隐藏文件夹的问题.vscode。该文件夹被检测为文本文件,错误告诉我该文件曾经busy且无法删除。
Daniel Eisenreich

2

即使一个文件夹可能不存在,也要删除该文件夹(避免使用Charles Chow的竞价条件),但在其他情况出错(例如权限问题,磁盘读取错误,该文件不是目录)时仍然存在错误

对于Python 3.x:

import shutil

def ignore_absent_file(func, path, exc_inf):
    except_instance = exc_inf[1]
    if isinstance(except_instance, FileNotFoundError):
        return
    raise except_instance

shutil.rmtree(dir_to_delete, onerror=ignore_absent_file)

Python 2.7代码几乎相同:

import shutil
import errno

def ignore_absent_file(func, path, exc_inf):
    except_instance = exc_inf[1]
    if isinstance(except_instance, OSError) and \
        except_instance.errno == errno.ENOENT:
        return
    raise except_instance

shutil.rmtree(dir_to_delete, onerror=ignore_absent_file)

1

使用os.walk,我将提出包含3个单行Python调用的解决方案:

python -c "import sys; import os; [os.chmod(os.path.join(rs,d), 0o777) for rs,ds,fs in os.walk(_path_) for d in ds]"
python -c "import sys; import os; [os.chmod(os.path.join(rs,f), 0o777) for rs,ds,fs in os.walk(_path_) for f in fs]"
python -c "import os; import shutil; shutil.rmtree(_path_, ignore_errors=False)"

第一个脚本chmod的所有子目录,第二个脚本chmod的所有文件。然后,第三个脚本将无障碍地删除所有内容。

我已经在Jenkins作业中的“ Shell脚本”中对此进行了测试(我不想将新的Python脚本存储到SCM中,这就是为什么要搜索单行解决方案的原因),并且它适用于Linux和Windows。


使用pathlib,您可以将前两个步骤组合为一个:[p.chmod(0o666) for p in pathlib.Path(_path_).glob("**/*")]
pepoluan

0

为了简单起见,可以使用os.system命令:

import os
os.system("rm -rf dirname")

显而易见,它实际上调用系统终端来完成此任务。


19
抱歉,这是Unpythonic和平台相关的。
Ami Tavory '16

0

我发现一种非常简单的方法来删除WINDOWS OS上的任何文件夹(甚至不为空)或文件。

os.system('powershell.exe  rmdir -r D:\workspace\Branches\*%s* -Force' %CANDIDATE_BRANCH)

0

对于Windows,如果目录不为空,并且您具有只读文件,或者出现诸如

  • Access is denied
  • The process cannot access the file because it is being used by another process

尝试这个, os.system('rmdir /S /Q "{}"'.format(directory))

rm -rf在Linux / Mac中等效。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.