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.py
的 onerror()
处理程序:
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】:
如果您使用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 作为终端仿真器而不是命令提示符【参考方案3】:
好吧,标记的解决方案对我不起作用...改为这样做:
os.system('rmdir /S /Q ""'.format(directory))
【讨论】:
这删除了目录本身。您能告诉我如何删除目录中的所有目录和文件吗?例如,如果我给出路径: myproject/dir1/ 那么它会删除 dir1 但我想删除 dir1 下的所有内容。【参考方案4】:我会说使用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))"【参考方案5】:
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,引发异常。在此处输入代码
【讨论】:
以上是关于shutil.rmtree 在 Windows 上因“访问被拒绝”而失败 [重复]的主要内容,如果未能解决你的问题,请参考以下文章
shutil 模块中 shutil.copy()、shutil.rmtree()、shutil.move()等基本函数用法介绍!
python笔记68 - os.remove()和shutil.rmtree()删除文件夹