Welcome, guest | Sign In | My Account | Store | Cart

This context manager ensures that a file's content is either replaced atomically with new contents or left unchanged. An exception or other error will not leave it empty or with partial content.

Python, 15 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from contextlib import contextmanager
import os, binascii

@contextmanager
def replacefile(name):
    tmpname = '%s.tmp-%s' % (name, binascii.hexlify(os.urandom(10)).decode('ascii'))
    try:
        with open(tmpname, 'w+') as f:
            yield f
        os.rename(tmpname, name)
    finally:
        try:
            os.unlink(tmpname)
        except OSError:
            pass

Using this context manager is similar to using open() in a 'with' statement:

with replacefile(filename) as f:
    f.write(...)

You can safely read and write the same file name to process it in-place:

with open(filename) as fin, replacefile(filename) as fout:
    fout.write(something(fin.read()))

This context manager depends on POSIX semantics for atomically replacing a file with rename(2). Do not use this on Windows.