views:

779

answers:

3

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.

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.

+3  A: 

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. Stackoverflow item on this.

>>> import uuid
>>> str(uuid.uuid1())
'64362370-93ef-11de-bf06-0023ae0b04b8'
hughdbrown
I am checking to see if it exists, I'm worried about a race condition as stated above.TemporaryFile doesn't have delete as a parameter. NamedTemporaryFile does though (in v2.6), Thanks for the pointer to this part of the python library I did not know existed.The UUID thing would probably work but seems a bit exotic for what I really need.
Mark0978
+12  A: 

Use os.open() with os.O_CREAT and os.O_EXCL to create the file. That will fail if the file already exists:

>>> 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:

>>> fd = os.open("y", os.O_WRONLY | os.O_CREAT | os.O_EXCL)
>>> f = os.fdopen(fd)  # f is now a standard Python file object
RichieHindle
Thanks, that is exactly what I was looking for.
Mark0978
if it is go ahead and accept the answer ;)
Bartosz Radaczyński
A: 

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.

This eliminates the race condition between the processes.

tgray