shutil.rmtree 在 Windows 上因“访问被拒绝”而失败 [重复]

Posted

技术标签:

【中文标题】shutil.rmtree 在 Windows 上因“访问被拒绝”而失败 [重复]【英文标题】:shutil.rmtree fails on Windows with 'Access is denied' [duplicate] 【发布时间】:2011-02-09 00:34:10 【问题描述】:

在 Python 中,当在包含只读文件的文件夹上运行 shutil.rmtree 时,会打印以下异常:

 File "C:\Python26\lib\shutil.py", line 216, in rmtree
   rmtree(fullname, ignore_errors, onerror)
 File "C:\Python26\lib\shutil.py", line 216, in rmtree
   rmtree(fullname, ignore_errors, onerror)
 File "C:\Python26\lib\shutil.py", line 216, in rmtree
   rmtree(fullname, ignore_errors, onerror)
 File "C:\Python26\lib\shutil.py", line 216, in rmtree
   rmtree(fullname, ignore_errors, onerror)
 File "C:\Python26\lib\shutil.py", line 216, in rmtree
   rmtree(fullname, ignore_errors, onerror)
 File "C:\Python26\lib\shutil.py", line 216, in rmtree
   rmtree(fullname, ignore_errors, onerror)
 File "C:\Python26\lib\shutil.py", line 216, in rmtree
   rmtree(fullname, ignore_errors, onerror)
 File "C:\Python26\lib\shutil.py", line 221, in rmtree
   onerror(os.remove, fullname, sys.exc_info())
 File "C:\Python26\lib\shutil.py", line 219, in rmtree
   os.remove(fullname)
WindowsError: [Error 5] Access is denied: 'build\\tcl\\tcl8.5\\msgs\\af.msg'

查看文件属性对话框,我注意到af.msg 文件设置为只读。

所以问题是:解决此问题的最简单 解决方法/修复方法是什么 - 考虑到我的意图是在 Windows 上做与 rm -rf build/ 等效的操作? (无需使用 unxutils 或 cygwin 等第三方工具 - 因为此代码旨在在安装了 Python 2.6 w/ PyWin32 的裸 Windows 安装上运行)

【问题讨论】:

shutil.rmtree 使用os.remove 删除文件。 os.remove 删除只读文件就好了(至少在 Unix 上)。 os.remove 无法在 Windows 上删除正在使用的文件。 相关:How to avoid “WindowsError: [Error 5] Access is denied” 根据我的经验,如果目录打开并且您运行代码并且与删除过程有关,而不是创建步骤,可能会出现此错误。 【参考方案1】:

看看这个问题:What user do python scripts run as in windows?

显然答案是将文件/文件夹更改为非只读,然后将其删除。

这是 @Sridhar Ratnakumar 在 cmets 中提到的来自 pathutils.pyonerror() 处理程序:

def onerror(func, path, exc_info):
    """
    Error handler for ``shutil.rmtree``.

    If the error is due to an access error (read only file)
    it attempts to add write permission and then retries.

    If the error is for another reason it re-raises the error.
    
    Usage : ``shutil.rmtree(path, onerror=onerror)``
    """
    import stat
    # Is the error an access error?
    if not os.access(path, os.W_OK):
        os.chmod(path, stat.S_IWUSR)
        func(path)
    else:
        raise

【讨论】:

嘿。我刚刚在voidspace.org.uk/downloads/pathutils.py 发现了onerror 处理程序 .. 发现是通过trac.pythonpaste.org/pythonpaste/ticket/359 即使此答案的 cmets 状态“将文件/文件夹更改为非只读”,我仍然收到对只读文件夹的访问被拒绝。不过,This 实现有效。 警告那些按原样复制粘贴此功能的人,请将import stat 移出该功能。当我将导入留在函数中并且函数位于类的 __del__ 方法中时,我收到了 RuntimeError: sys.meta_path must be a list of import hooks 解决方案的“else raise”部分不会引发异常。来自 Python 文档:“不会捕获由 onerror 引发的异常。” docs.python.org/2/library/shutil.html#shutil.rmtree【参考方案2】:

我会说使用os.walk 实现您自己的rmtree,以确保在尝试删除每个文件之前对每个文件使用os.chmod 进行访问。

类似这样的东西(未经测试):

import os
import stat

def rmtree(top):
    for root, dirs, files in os.walk(top, topdown=False):
        for name in files:
            filename = os.path.join(root, name)
            os.chmod(filename, stat.S_IWUSR)
            os.remove(filename)
        for name in dirs:
            os.rmdir(os.path.join(root, name))
    os.rmdir(top)      

【讨论】:

这几乎是正确的 - Windows 仅支持 stat.S_IWRITE(这就是你想要的) - docs.python.org/library/os.html#os.chmod 我确实测试了os.chmod(filename, stat.S_IWUSR) 删除了只读标志,所以它在 WinXP 上运行。考虑到这是文档对stat.S_IWRITE 所说的:“S_IWUSR 的 Unix V7 同义词”(docs.python.org/library/stat.html#stat.S_IWRITE),我认为我的代码无论如何都是正确的。 很好,文件路径太长,这似乎是唯一的方法。建议提交或更改 shutil.rmtree。 这适用于 Windows 10 中 python 2.7 中的 stat.S_IWRITE 用于只读文件。 很好,但是在存在嵌套子文件夹时失败......除非您通过将“os.rmdir(os.path.join(root, name))”替换为“rmtree(os.path .join(root, name))"【参考方案3】:

好吧,标记的解决方案对我不起作用...改为这样做:

os.system('rmdir /S /Q ""'.format(directory))

【讨论】:

这删除了目录本身。您能告诉我如何删除目录中的所有目录和文件吗?例如,如果我给出路径: myproject/dir1/ 那么它会删除 dir1 但我想删除 dir1 下的所有内容。【参考方案4】:
shutil.rmtree(path,ignore_errors=False,onerror=errorRemoveReadonly) 
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

如果设置了ignore_errors,则忽略错误;否则,如果出现错误 设置时,调用它来处理带有参数的错误(func, path, exc_info) 其中 func 是 os.listdir、os.remove 或 os.rmdir; path 是导致它失败的函数的参数;和 exc_info 是 sys.exc_info() 返回的元组。如果忽略_错误 为 false 且 onerror 为 None,引发异常。在此处输入代码

【讨论】:

【参考方案5】:

如果您使用cygwin 运行脚本,则可以使用subprocess.call

from subprocess import call
call("rm -rf build/", shell=True)

当然它只适用于 cygwin/bash 模拟器。

【讨论】:

在 Windows 上调用 rm -rf?我不这么认为。 很奇怪。我为 Windows (cmder) 使用了一个类似 unix 的控制台模拟器。 subprocess.call 方法在我从该控制台运行脚本时有效,但如果我从默认的“命令提示符”运行它则无效 您在否决之前尝试过吗?我确认它可以在 Windows 下运行 @besil,是的,call('rm -rf "C:\\Temp\\tmp7cm15k\\"', shell=True) 导致 'rm' is not recognized as an internal or external command, operable program or batch file. mh,我认为它对我有用,因为我使用 Cygwin 作为终端仿真器而不是命令提示符

以上是关于shutil.rmtree 在 Windows 上因“访问被拒绝”而失败 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

shutil 模块中 shutil.copy()、shutil.rmtree()、shutil.move()等基本函数用法介绍!

python笔记68 - os.remove()和shutil.rmtree()删除文件夹

python-os.rmdir与shutil.rmtree的区别和用法

shutil模块详解

shutil模块

shutil模块