How to make file creation an atomic operation?
Write data to a temporary file and when data has been successfully written, rename the file to the correct destination file e.g
with open(tmpFile, 'w') as f:
f.write(text)
# make sure that all data is on disk
# see http://stackoverflow.com/questions/7433057/is-rename-without-fsync-safe
f.flush()
os.fsync(f.fileno())
os.replace(tmpFile, myFile) # os.rename pre-3.3, but os.rename won't work on Windows
According to doc http://docs.python.org/library/os.html#os.replace
Rename the file or directory
src
todst
. If dst is a non-empty directory,OSError
will be raised. Ifdst
exists and is a file, it will be replaced silently if the user has permission. The operation may fail ifsrc
anddst
are on different filesystems. If successful, the renaming will be an atomic operation (this is a POSIX requirement).
Note:
It may not be atomic operation if src and dest locations are not on same filesystem
os.fsync
step may be skipped if performance/responsiveness is more important than the data integrity in cases like power failure, system crash etc
Atomic file write operations (cross platform)
AFAIK no.
And the reason is that for such an atomic operation to be possible, there has to be OS support in the form of a transactional file system. And none of the mainstream operating system offer a transactional file system.
EDIT - I'm wrong for POSIX-compliant systems at least. The POSIX rename
syscall performs an atomic replace if a file with the target name already exists ... as pointed out by @janneb. That should be sufficient to do the OP's operation atomically.
However, the fact remains that the Java File.renameTo()
method is explicitly not guaranteed to be atomic, so it does not provide a cross-platform solution to the OP's problem.
EDIT 2 - With Java 7 you can use java.nio.file.Files.move(Path source, Path target, CopyOption... options)
with copyOptions and ATOMIC_MOVE
. If this is not supported (by the OS / file system) you should get an exception.
Create and write a file in one atomic operation on OS level
I'd suggest you to write temporary file and then rename it to your file. I am not sure this operation is implemented in java as atomic for all operating system but at least on Unix you have a chance because I think it uses the same call as mv
that is atomic.
It will not be truly atomic on windows, I guess. It will be "almost atomic" that is enough for most applications.
Atomically creating a file if it doesn't exist in Python
You can use os.open with os.O_CREAT | os.O_EXCL
flags which will fail if the file exists, they are according to the docs available on Unix and Windows but I am not sure if atomic file creation exists on windows or not:
os.open("filename", os.O_CREAT | os.O_EXCL)
From the linux open man page:
O_EXCL
If O_CREAT and O_EXCL are set, open() shall fail if the file exists. The check for the existence of the file and the creation of the file if it does not exist shall be atomic with respect to other threads executing open() naming the same filename in the same directory with O_EXCL and O_CREAT set. If O_EXCL and O_CREAT are set, and path names a symbolic link, open() shall fail and set errno to [EEXIST], regardless of the contents of the symbolic link. If O_EXCL is set and O_CREAT is not set, the result is undefined.
Not sure what you want to do if the file exists but you just need to catch a FileExistsError
when the file does already exist:
import os
def try_make_file(filename):
try:
os.open(filename, os.O_CREAT | os.O_EXCL)
return True
except FileExistsError:
return False
Implementing atomic file writes in a nontransactional filesystem
Your steps can be simplified further:
- Write new content to a temporary file New
- Delete Original file
- Move New to Original
On startup:
- If Original does not exist but New does, the process was interrupted before step 3, move New to Original.
- If Original and New both exist, the process was interrupted before step 2, delete New.
I have used this in managing configuration files and have never encountered a problem from this process.
Atomically write byte[] to file
Atomic writes to files are not possible. Operating systems don't support it, and since they don't, programming language libraries can't do it either.
The best you are going to get with a files in a conventional file system is atomic file renaming; i.e.
write new file into same file system as the old one
use
FileDescriptor.sync()
to ensure that new file is writtenrename the new file over the old one; e.g. using
java.nio.file.Files.move(Path source, Path target,
CopyOption... options)with CopyOptions
ATOMIC_MOVE
. According to the javadocs, this may not be supported, but if it isn't supported you should get an exception.
But note that the atomicity is implemented in the OS, and if the OS cannot give strong enough guarantees, you are out of luck.
(One issue is what might happen in the event of a hard disk error. If the disk dies completely, then atomicity is moot. But if the OS is still able to read data from the disk after the failure, then the outcome may depend on the OS'es ability to repair a possibly inconsistent file system.)
atomic operations on a file from different processes
You can use a Named Mutex to share a lock between processes:
const int MAX_RETRY = 50;
const int DELAY_MS = 200;
bool Success = false;
int Retry = 0;
// Will return an existing mutex if one with the same name already exists
Mutex mutex = new Mutex(false, "MutexName");
mutex.WaitOne();
try
{
while (!Success && Retry < MAX_RETRY)
{
using (StreamWriter Wr = new StreamWriter(ConfPath))
{
Wr.WriteLine("My content");
}
Success = true;
}
}
catch (IOException)
{
Thread.Sleep(DELAY_MS);
Retry++;
}
finally
{
mutex.ReleaseMutex();
}
Related Topics
How to Profile Python Code Line-By-Line
Split a Python List into Other "Sublists" I.E Smaller Lists
Usage of Sys.Stdout.Flush() Method
How to Change Default Anaconda Python Environment
How to Unzip a List of Tuples into Individual Lists
Change User-Agent for Selenium Web-Driver
Timeout for Python Requests.Get Entire Response
Validate Ssl Certificates with Python
How to Find Numeric Columns in Pandas
Multiple Variables in a 'With' Statement
How to Set Class Attributes from Variable Arguments (Kwargs) in Python
Accessing Mp3 Metadata with Python
Convert Rgba Png to Rgb with Pil
Check If Two Unordered Lists Are Equal
How to Dynamically Compose an or Query Filter in Django