Bare Excepts

sjdevnull at yahoo.com sjdevnull at yahoo.com
Fri Jan 15 00:36:59 CET 2010


On Jan 2, 9:35 pm, Dave Angel <da... at ieee.org> wrote:
> Steven D'Aprano wrote:
> > On Sat, 02 Jan 2010 09:40:44 -0800, Aahz wrote:
>
> >> OTOH, if you want to do something different depending on whether the
> >> file exists, you need to use both approaches:
>
> >> if os.path.exists(fname):
> >>     try:
> >>         f = open(fname, 'rb')
> >>         data = f.read()
> >>         f.close()
> >>         return data
> >>     except IOError:
> >>         logger.error("Can't read: %s", fname) return ''
> >> else:
> >>     try:
> >>         f = open(fname, 'wb')
> >>         f.write(data)
> >>         f.close()
> >>     except IOError:
> >>         logger.error("Can't write: %s", fname)
> >>     return None
>
> > Unfortunately, this is still vulnerable to the same sort of race
> > condition I spoke about.
>
> > Even more unfortunately, I don't know that there is any fool-proof way of
> > avoiding such race conditions in general. Particularly the problem of
> > "open this file for writing only if it doesn't already exist".
>
> > <snip>
>
> In Windows, there is  a way to do it.  It's just not exposed to the
> Python built-in function open().  You use the CreateFile() function,
> with /dwCreationDisposition/  of CREATE_NEW.
>
> It's atomic, and fails politely if the file already exists.
>
> No idea if Unix has a similar functionality.

It does.   In Unix, you'd pass O_CREAT|O_EXCL to the open(2) system
call (O_CREAT means create a new file, O_EXCL means exclusive mode:
fail if the file exists already).

The python os.open interface looks suspiciously like the Unix system
call as far as invocation goes, but it wraps the Windows functionality
properly for the relevant flags.  The following should basically work
on both OSes (though you'd want to specify a Windows filename, and
also set os.O_BINARY or os.O_TEXT as needed on Windows):

import os

def exclusive_open(fname):
    rv = os.open(fname, os.O_RDWR|os.O_CREAT|os.O_EXCL)
    return os.fdopen(rv)

first = exclusive_open("/tmp/test")
print "SUCCESS: ", first
second = exclusive_open("/tmp/test")
print "SUCCESS: ", second




Run that and you should get:
SUCCESS <open file '<fdopen>', mode 'r' at 0xb7f72c38>
Traceback (most recent call last):
  File "testopen.py", line 9, in <module>
    second = exclusive_open("/tmp/test")
  File "testopen.py", line 4, in exclusive_open
    rv = os.open(fname, os.O_RDWR|os.O_CREAT|os.O_EXCL)
OSError: [Errno 17] File exists: '/tmp/test'



More information about the Python-list mailing list