什么是在 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) 的好方法的主要内容,如果未能解决你的问题,请参考以下文章

Python ZipFile 路径分隔符

Python基础知识——Windows上使用python

windows10文件夹返回上一级,自动回到最上方怎么解

是否可以在 Windows XP 上使用 .BAT 命令解压缩 .ZIP 文件?

如何在 Windows 上使用 Git Bash 解压缩 .gz 文件?

什么是在 Windows 环境中使用 shell 脚本的好 IDE? [关闭]