Skip to content

Instantly share code, notes, and snippets.

@codeslinger
Created August 3, 2008 01:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save codeslinger/3792 to your computer and use it in GitHub Desktop.
Save codeslinger/3792 to your computer and use it in GitHub Desktop.
# vim:set ts=4 sw=4 et ai:
from __future__ import with_statement
"""
:Author: Toby DiPasquale <toby@cbcg.net>
:Copyright: Copyright (c) 2008 Toby DiPasquale. Free for use for any purpose
by anyone forever.
Introduction
============
Built from the recommendations found in the "Eat My Data" talk by Stewart
Smith of MySQL AB (online here: http://www.flamingspork.com/talks/), this
module will help you avoid data corruption issues on multiple platforms.
This module requires Python 2.5 or higher.
"""
__docformat__ = "restructuredtext"
import sys
import os
#
# Mac OS X's fsync() doesn't really sync to disk; instead we have
# to issue this fcntl() to make sure the data is on disk on that
# platform.
#
if sys.platform == 'darwin':
# 51 == F_FULLSYNC on Mac OS X (/usr/include/sys/fcntl.h)
import fcntl
_sync = lambda fd : fcntl.fcntl(fd, 51)
else:
_sync = os.fsync
def save(path, data, mode='w', offset=None, whence=os.SEEK_SET):
"""
Write `data` into `path` in the safest way possible vis a vis avoiding
data corruption.
:Parameters:
path : str
path to file into which to write `data`
data : str
contents to write to `path`
mode : str
mode with which to open `path` (e.g. ``'w'`` for writing, ``'a'``
for appending, etc.; see `open` docs for details)
offset : long
byte offset into `path` into which to write `data`
whence : int
how to interpret `offset` in terms of positioning in the file;
see `os.seek` for details on valid arguments
:raise `OSError`: raised by underlying OS ops in case of error
:raise `IOError`: raised by underlying file ops in case of error
"""
tmp = _tempfile(path)
with open(tmp, mode) as f:
if offset:
f.seek(offset, whence)
f.write(data)
f.flush()
_sync(f.fileno())
os.rename(tmp, path)
def _tempfile(path):
"""
Create a tempfile name for the given `path`.
:Parameters:
path : str
original file path
:rtype: str
:return: path to tempfile for `path`
"""
return '%s.tmp' % path
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment