Crates.io | atomic-write-file |
lib.rs | atomic-write-file |
version | 0.2.2 |
source | src |
created_at | 2023-08-22 21:46:22.809241 |
updated_at | 2024-11-03 22:04:15.0677 |
description | Write files atomically to a file system |
homepage | |
repository | https://github.com/andreacorbellini/rust-atomic-write-file |
max_upload_size | |
id | 951362 |
size | 86,133 |
This is a Rust crate that offers functionality to write and overwrite files atomically, that is: without leaving the file in an intermediate state. Either the new contents of the files are written to the filesystem, or the old contents (if any) are preserved.
This crate implements two main structs: AtomicWriteFile
and OpenOptions
,
which mimic the standard std::fs::File
and std::fs::OpenOptions
as much as
possible.
This crate supports all major platforms, including: Unix systems, Windows, and WASI.
This crate is throughly tested to ensure the integrity of the files it creates. In particular, it ships with tests that simulate kernel panics on Linux and check the file contents afterwards. You can see those tests in action on the dedicated GitHub workflow.
Consider the following snippet of code to write a configuration file in JSON format:
use std::io::Write;
use std::fs::File;
let mut file = File::options()
.write(true)
.create(true)
.open("config.json")?;
writeln!(file, "{{")?;
writeln!(file, " \"key1\": \"value1\",")?;
writeln!(file, " \"key2\": \"value2\"")?;
writeln!(file, "}}")?;
This code opens a file named config.json
, truncates its contents (if the file
already existed), and writes the JSON content line-by-line.
If the code is interrupted before all of the writeln!
calls are completed
(because of a panic, or a signal is received, or the process is killed, or a
filesystem error occurs), then the file will be left in a broken state: it will
not contain valid JSON data, and the original contents (if any) will be lost.
AtomicWriteFile
solves this problem by placing the new contents into the
destination file only after it has been completely written to the filesystem.
The snippet above can be rewritten using AtomicWriteFile
instead of File
as
follows:
use std::io::Write;
use atomic_write_file::AtomicWriteFile;
let mut file = AtomicWriteFile::options()
.open("config.json")?;
writeln!(file, "{{")?;
writeln!(file, " \"key1\": \"value1\",")?;
writeln!(file, " \"key2\": \"value2\"")?;
writeln!(file, "}}")?;
file.commit()?;
Note that this code is almost the same as the original, except that it now uses
AtomicWriteFile
instead of File
and there's an additional call to
commit()
.
If the code is interrupted early, before the call to commit()
, the original
file config.json
will be left untouched. Only if the new contents are fully
written to the filesystem, config.json
will get them.
Reference, examples, internal details, and limitations are all available on docs.rs/atomic-write-file.