[issue8604] Adding an atomic FS write API
STINNER Victor
report at bugs.python.org
Thu May 27 01:18:52 CEST 2010
STINNER Victor <victor.stinner at 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 <report at bugs.python.org>
<http://bugs.python.org/issue8604>
_______________________________________
More information about the Python-bugs-list
mailing list