Currently I have a loop that tries to find an unused filename by adding suffixes to a filename string. Once it fails to find a file, it uses the name that failed to open a new file wit that name. Problem is this code is used in a website and there could be multiple attempts to do the same thing at the same time, so a race condition exists.
目前,我有一个循环,它试图通过在文件名字符串中添加后缀来查找未使用的文件名。一旦它找不到一个文件,它就会使用未能打开一个新文件名的名称。问题是,这个代码是在一个网站上使用的,而且可能有多个尝试同时做同一件事,所以存在一个竞态条件。
How can I keep python from overwriting an existing file, if one is created between the time of the check and the time of the open in the other thread.
如果在检查的时间和在另一个线程中打开的时间之间创建了一个现有的文件,那么如何防止python覆盖现有的文件。
I can minimize the chance by randomizing the suffixes, but the chance is already minimized based on parts of the pathname. I want to eliminate that chance with a function that can be told, create this file ONLY if it doesn't exist.
我可以通过随机化后缀来最小化这个机会,但是根据路径名的部分,概率已经最小化了。我想用一个可以被告知的函数来消除这个机会,只在它不存在的情况下创建这个文件。
I can use win32 functions to do this, but I want this to work cross platform because it will be hosted on linux in the end.
我可以使用win32函数来实现这一点,但我希望它能够工作跨平台,因为它最终将在linux上托管。
3 个解决方案
#1
37
Use os.open()
with os.O_CREAT
and os.O_EXCL
to create the file. That will fail if the file already exists:
使用os.open()操作系统。O_CREAT和操作系统。O_EXCL创建文件。如果文件已经存在,那将会失败:
>>> fd = os.open("x", os.O_WRONLY | os.O_CREAT | os.O_EXCL)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 17] File exists: 'x'
Once you've created a new file, use os.fdopen()
to turn the handle into a standard Python file object:
创建新文件后,使用os.fdopen()将句柄转换为标准Python文件对象:
>>> fd = os.open("y", os.O_WRONLY | os.O_CREAT | os.O_EXCL)
>>> f = os.fdopen(fd, "w") # f is now a standard Python file object
Edit: From Python 3.3, the builtin open()
has an x
mode that means "open for exclusive creation, failing if the file already exists".
Edit:从Python 3.3中,builtin open()有一个x模式,这意味着“如果文件已经存在,则为独占创建打开”。
#2
7
If you are concerned about a race condition, you can create a temporary file and then rename it.
如果您关心一个竞态条件,您可以创建一个临时文件,然后重命名它。
>>> import os
>>> import tempfile
>>> f = tempfile.NamedTemporaryFile(delete=False)
>>> f.name
'c:\\users\\hughdb~1\\appdata\\local\\temp\\tmpsmdl53'
>>> f.write("Hello world")
>>> f.close()
>>> os.rename(f.name, r'C:\foo.txt')
>>> if os.path.exists(r'C:\foo.txt') :
... print 'File exists'
...
File exists
Alternatively, you can create the files using a uuid in the name. * item on this.
或者,您可以使用名称中的uuid创建文件。*项目。
>>> import uuid
>>> str(uuid.uuid1())
'64362370-93ef-11de-bf06-0023ae0b04b8'
#3
0
If you have an id
associated with each thread / process that tries to create the file, you could put that id in the suffix somewhere, thereby guaranteeing that no two processes can use the same file name.
如果您有一个与试图创建文件的每个线程/进程相关联的id,那么您可以将该id放到后缀中,从而保证没有两个进程可以使用相同的文件名。
This eliminates the race condition between the processes.
这消除了进程之间的竞争条件。
#1
37
Use os.open()
with os.O_CREAT
and os.O_EXCL
to create the file. That will fail if the file already exists:
使用os.open()操作系统。O_CREAT和操作系统。O_EXCL创建文件。如果文件已经存在,那将会失败:
>>> fd = os.open("x", os.O_WRONLY | os.O_CREAT | os.O_EXCL)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 17] File exists: 'x'
Once you've created a new file, use os.fdopen()
to turn the handle into a standard Python file object:
创建新文件后,使用os.fdopen()将句柄转换为标准Python文件对象:
>>> fd = os.open("y", os.O_WRONLY | os.O_CREAT | os.O_EXCL)
>>> f = os.fdopen(fd, "w") # f is now a standard Python file object
Edit: From Python 3.3, the builtin open()
has an x
mode that means "open for exclusive creation, failing if the file already exists".
Edit:从Python 3.3中,builtin open()有一个x模式,这意味着“如果文件已经存在,则为独占创建打开”。
#2
7
If you are concerned about a race condition, you can create a temporary file and then rename it.
如果您关心一个竞态条件,您可以创建一个临时文件,然后重命名它。
>>> import os
>>> import tempfile
>>> f = tempfile.NamedTemporaryFile(delete=False)
>>> f.name
'c:\\users\\hughdb~1\\appdata\\local\\temp\\tmpsmdl53'
>>> f.write("Hello world")
>>> f.close()
>>> os.rename(f.name, r'C:\foo.txt')
>>> if os.path.exists(r'C:\foo.txt') :
... print 'File exists'
...
File exists
Alternatively, you can create the files using a uuid in the name. * item on this.
或者,您可以使用名称中的uuid创建文件。*项目。
>>> import uuid
>>> str(uuid.uuid1())
'64362370-93ef-11de-bf06-0023ae0b04b8'
#3
0
If you have an id
associated with each thread / process that tries to create the file, you could put that id in the suffix somewhere, thereby guaranteeing that no two processes can use the same file name.
如果您有一个与试图创建文件的每个线程/进程相关联的id,那么您可以将该id放到后缀中,从而保证没有两个进程可以使用相同的文件名。
This eliminates the race condition between the processes.
这消除了进程之间的竞争条件。