STINNER Victor <victor.stin...@haypocalc.com> added the comment:

> This sounds silly to me. You can write a file in two lines:
>
> with open("foo", "wb") as f:
>    f.write(contents)

If the disk is full, write fails and the new file only contains a part of 
'contents'. If the file does already exist and the write fails, the original 
content is lost.

The correct pattern is something like:

@contextlib.contextmanager
def atomic_write(filename):
  tempname = filename + ".tmp"
  out = open(tempname, "w")
  try:
     yield out
     if hasattr('os', 'fsync'):
        os.fsync(out.fileno())
     out.close()
     if os.name in ('nt', 'ce'):
        os.unlink(filename)
        # ... hope that it doesn't fail here ...
     os.rename(tempname, filename)
  except:
     out.close()
     os.unlink(tempname)
     raise

Remarks:
 - call fsync() to ensure that the new file content is written on disk. it does 
nothing on Mac OS X
 - on Windows, it's not possible to rename a to b if b does already exist. New 
Windows versions has an atomic function: MoveFileTransacted(). Older versions 
have MoveFileEx(MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH) and 
ReplaceFile()

This context manager is *not* atomic on any OS. It's only atomic on some OS, 
and it may depends on the kernel version (see recent discussions about 
ext3/ext4, fsync and write barrier).

----------
nosy: +haypo

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue8604>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to