什么是在 Windows 上使用 Python 解决虚假 OSError, 13 (EACCES) 的好方法
Posted
技术标签:
【中文标题】什么是在 Windows 上使用 Python 解决虚假 OSError, 13 (EACCES) 的好方法【英文标题】:What is a good solution to a bogus OSError, 13 (EACCES) using Python on Windows 【发布时间】:2011-06-04 07:40:25 【问题描述】:代码如下:
def make_dir(dir_name):
if os.path.exists(dir_name):
shutil.rmtree(dir_name)
try:
os.makedirs(dir_name)
except OSError, e:
print "ErrorNo: %s (%s)" % (e.errno, errno.errorcode[e.errno])
raise
如果目录已经存在,我得到以下信息:
ErrorNo: 13 (EACCES)
Traceback (most recent call last):
File "run_pnoise.py", line 167, in <module>
make_dir("prep_dat")
File "run_pnoise.py", line 88, in make_dir
os.makedirs(dir_name)
File "c:\Program Files (x86)\Python27\lib\os.py", line 157, in makedirs
mkdir(name, mode)
WindowsError: [Error 5] Access is denied: 'prep_dat'
如果我再次运行该程序,它可以工作,这表明该程序确实可以访问目录,因为 shutil.rmtree 调用显然是有效的。我想出了一个解决方法,我将发布。但是,是否有更好的解释和/或解决方法?
我的假设是 shutil.rmtree 调用在操作系统完全删除所有文件和子目录之前返回。此外,由于 shutil.rmtree 调用没有引发异常,因此 makedirs 调用上的任何 EACCESS (13) 错误都可能是虚假的。我的尝试(根据 Apalala 的评论修改):
def make_dir(dir_name):
retry = True
if os.path.exists(dir_name):
shutil.rmtree(dir_name)
while retry:
try:
# per Apalala, sleeping before the makedirs() eliminates the exception!
time.sleep(0.001)
os.makedirs(dir_name)
except OSError, e:
#time.sleep(0.001) # moved to before the makedirs() call
#print "ErrorNo: %s (%s)" % (e.errno, errno.errorcode[e.errno])
if e.errno != 13: # eaccess
raise
else:
retry = False
这似乎工作可靠。其他帖子中提到了竞争条件问题,但这似乎不太可能,并且可能会导致不同的异常。
【问题讨论】:
我希望如果在调用makedirs()
之前调用sleep()
,则不应引发任何异常。为了调试起见,您可以在调用 makedirs()
之前添加 while os.path.isdir(dir_name): print 'still there'
。
你的假设是正确的。 Win API DeleteFile
只是将目录标记为删除,所以当调用返回时,该目录仍然存在。因此,您有以下 makedirs 调用的竞争条件。在 unix 上,取消链接只会删除名称,因此不会发生冲突。
【参考方案1】:
我遇到了同样的问题,这看起来与我的解决方案相似,除了我在睡觉 (0.1)。
【讨论】:
【参考方案2】:你不能简单地使用«except»语句吗?
def make_dir(dir_name):
retry = True
if os.path.exists(dir_name):
shutil.rmtree(dir_name)
while retry:
try:
os.makedirs(dir_name)
except OSError, e:
time.sleep(0.001)
if e.errno != 13: # eaccess
raise
except WindowsError:
# (do some stuff)
else:
retry = False
它应该可以工作,不是吗?!
【讨论】:
我不明白这与我的提议有何实质性不同。我错过了什么?except WindowsError
永远不会发生,因为 WindowsError 是 OSError 的子类,因此将触发之前的 `except OSError'。【参考方案3】:
在您之前的帖子中,您说程序引发了 «WindowsError» 异常:
WindowsError: [Error 5] Access is denied: 'prep_dat'
您的代码可以使用 «except» 语句处理 «OSError» 异常,但它不能处理 «WindowsError» 异常...如果您想处理 «WindowsError» 异常,您必须使用如下«except» 语句:
except WindowsError:
# (do some stuff)
请注意,您可以像这样处理任何异常:
except Exception, e:
# this code will catch all raised exceptions. The variable «e» contains an instance of the raised exception.
【讨论】:
这是不正确的。 WindowsError 是 OSError 的子类,因此捕获 OSError 会得到两者。以上是关于什么是在 Windows 上使用 Python 解决虚假 OSError, 13 (EACCES) 的好方法的主要内容,如果未能解决你的问题,请参考以下文章
是否可以在 Windows XP 上使用 .BAT 命令解压缩 .ZIP 文件?