关于python:shutil.rmtree在Windows上失败并且“访问被拒绝”

shutil.rmtree fails on Windows with 'Access is denied'

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 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上运行)


检查这个问题:

在Windows中,python脚本的运行方式是什么?

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

以下是@sridhar ratnakumar在评论中提到的来自EDOCX1[1]的EDOCX1[0]处理程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
    if not os.access(path, os.W_OK):
        # Is the error an access error ?
        os.chmod(path, stat.S_IWUSR)
        func(path)
    else:
        raise


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

类似这样的事情(未测试):

1
2
3
4
5
6
7
8
9
10
11
12
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)


嗯,标记的解决方案对我不起作用…而是这样做了:

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

1
2
3
4
5
6
7
8
9
10
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

如果设置了"忽略错误",则忽略错误;否则,如果设置了"忽略错误"如果设置了,则调用它以使用参数(func,路径,exc_info),其中func是os.listdir、os.remove或os.rmdir;path是导致它失败的函数的参数;并且exc-info是sys.exc-info()返回的元组。如果忽略错误为false,onerror为none,引发异常。请在此处输入代码


一个简单的解决方法是使用subprocess.call

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

为了执行你想要的一切。