我有一个urllib2的缓存模块,其偶尔崩溃由于以下代码:

if not os.path.exists(self.cache_location):
    os.mkdir(self.cache_location)

的问题是,由正被执行的第二行的时候,该文件夹可以存在,并且将错误:

  File ".../cache.py", line 103, in __init__
    os.mkdir(self.cache_location)
OSError: [Errno 17] File exists: '/tmp/examplecachedir/'

这是因为脚本是同步推出了无数次,通过第三方的代码,我在无法控制的。

代码(前我试图修复错误)可被这里找到,在github

我不能使用 tempfile.mkstemp ,因为它解决了通过使用一个随机命名目录( tempfile.py源这里的竞争条件),它会破坏高速缓存的目的。

我不想简单地丢弃该错误,仿佛该文件夹名称存在作为文件(一个不同的错误),例如被升高的相同的错误errno的17错误:

$ touch blah
$ python
>>> import os
>>> os.mkdir("blah")
Traceback (most recent call last):
  File "", line 1, in 
OSError: [Errno 17] File exists: 'blah'
>>>

我无法通过threading.RLock作为代码从多个进程调用。

所以,我试图写一个简单的基于文件的锁(该版本可以是发现这里),但有一个问题:它创建了一个锁文件级别,所以/tmp/example.lock/tmp/example/,如果你使用的休息作为高速缓存目录/tmp/(因为它试图使/tmp.lock)..

在短,我需要缓存urllib2响应到光盘上。要做到这一点,我需要访问一个已知的目录(创建它,如果需要的话),在多进程安全的方式。这需要对OS X,Linux和Windows的工作。

思考?唯一的替代解决方案,我能想到的是使用的SQLite3存储,而不是文件重写高速缓存模块。

有帮助吗?

解决方案

在Python 3.x中,你可以使用os.makedirs(path, exists_ok=True),如果这样的目录存在,不会引发任何异常。如果文件具有相同的名称作为所请求的目录(FileExistsError: [Errno 17])存在,它会提高path

与验证:

import os

parent = os.path.dirname(__file__)

target = os.path.join(parent, 'target')

os.makedirs(target, exist_ok=True)
os.makedirs(target, exist_ok=True)

os.rmdir(target)

with open(target, 'w'):
    pass

os.makedirs(target, exist_ok=True)

其他提示

代替

if not os.path.exists(self.cache_location):
    os.mkdir(self.cache_location)

您可以做

try:
    os.makedirs(self.cache_location)
except OSError:
    pass

如你最终会使用相同的功能

<子>免责声明:我不知道如何Python的,这可能是


使用SQLite3,的可能的是一个有点矫枉过正,但会增加的很多的功能性和灵活性,以你的使用情况。

如果您需要做大量的“选择”,并发插入和过滤的,这是一个伟大的想法,使用SQLite3,因为它不会增加太多的复杂性比简单的文件(也可以说,它消除了复杂性)。


重读你的问题(和评论),我可以更好地了解您的问题。

什么是一个的文件可以创建相同的竞争条件的可能性?

如果它足够小,那么我会做这样的事情:

if not os.path.isfile(self.cache_location):
    try:
        os.makedirs(self.cache_location)
    except OSError:
        pass

此外,阅读你的代码,我会改变

else:
    # Our target dir is already a file, or different error,
    # relay the error!
    raise OSError(e)

else:
    # Our target dir is already a file, or different error,
    # relay the error!
    raise

,因为它真的是你想要的,Python来再加注完全相同的例外<子>(只是吹毛求疵)。


一两件事,可以是可能是使用你(类Unix只)。

我结束了的代码是:

import os
import errno

folder_location = "/tmp/example_dir"

try:
    os.mkdir(folder_location)
except OSError as e:
    if e.errno == errno.EEXIST and os.path.isdir(folder_location):
        # File exists, and it's a directory,
        # another process beat us to creating this dir, that's OK.
        pass
    else:
        # Our target dir exists as a file, or different error,
        # reraise the error!
        raise

你能捕捉到了异常,然后测试该文件是否存在目录或不?

当你有竞争条件经常EAFP(更容易请求原谅比许可)的作品更好的是LBYL(三思而后行)

错误检查策略

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top