Struct atomic_write_file::AtomicWriteFile
source · pub struct AtomicWriteFile { /* private fields */ }
Expand description
A file whose contents become visible to users only after the file is committed.
An AtomicWriteFile
is a file that is assigned to a path, but whose contents won’t appear at
that path until the file is committed. If AtomicWriteFile
is used
to open a file that already exists, the contents of the existing file will remain available
until the AtomicWriteFile
is committed. During that time, the AtomicWriteFile
may be used
to write new contents, but these new contents won’t be visible until after the file is
committed.
Internally, AtomicWriteFile
is implemented by initally opening a temporary file, and then
renaming the temporary file to its final path on commit. See the module-level
documentation for more details about the implementation.
An AtomicWriteFile
is automatically discarded when it goes out of scope (when it gets
dropped). Any error that occurs on drop is ignored. For this reason, if the file should not be
committed, it is highly recommended that AtomicWriteFile
is discarded explicitly using the
discard()
method, which allows callers to detect errors on
cleanup. See committing or discarding changes below for
more information.
§Opening an AtomicWriteFile
There are two ways to obtain an AtomicWriteFile
struct:
The first method opens a file at the specified path with some default options. The second
method using OpenOptions
allows configuring how the file is opened.
§Compatibility with std::fs::File
AtomicWriteFile
implements the same methods and traits of std::fs::File
, and aims to be
as much compatible with File
as possible. In fact, AtomicWriteFile
can be
dereferenced into a File
struct: this means that you can use all methods provided by
File
directly on an AtomicWriteFile
(just like you can use all of str
methods on a
String
).
A reference to the wrapped File
struct may also be explicitly obtained using
as_file()
and as_file_mut()
.
§Committing or discarding changes
AtomicWriteFile
provides two additional methods that are not provided by File
:
commit()
and discard()
. These
methods can be called to save the new contents to the file path, or to destroy the new contents
and leave the original file (if any) unchaged, respectively.
Changes are automatically discarded also when AtomicWriteFile
is dropped. Therefore calling
discard()
is not mandatory, but it is highly recommended because
the Drop
implementation ignores all errors.
§Cloning
Cloning a AtomicWriteFile
is not possible, because this would result in ambiguity and race
conditions when committing the file and its clones. It is however possible to clone the
underlaying File
struct using try_clone()
. Writes to this cloned
File
however won’t be atomic after the AtomicWriteFile
is committed.
§Examples
Opening a file, writing new contents, and committing the changes:
use std::io::Write;
use atomic_write_file::AtomicWriteFile;
let mut file = AtomicWriteFile::open("foo.txt")?; // if "foo.txt" already exists, it is not
// initially truncated or deleted
writeln!(file, "hello")?; // "hello" is written to a temporary location; "foo.txt" (if it
// exists) keeps its old contents after this write
file.commit()?; // only now "foo.txt" gets swapped with the new contents ("hello")
Implementations§
source§impl AtomicWriteFile
impl AtomicWriteFile
sourcepub fn open<P: AsRef<Path>>(path: P) -> Result<AtomicWriteFile>
pub fn open<P: AsRef<Path>>(path: P) -> Result<AtomicWriteFile>
Opens an atomically-written file at path
.
See OpenOptions
for more details.
§Examples
use atomic_write_file::AtomicWriteFile;
let file = AtomicWriteFile::open("foo.txt");
sourcepub fn options() -> OpenOptions
pub fn options() -> OpenOptions
Creates a new OpenOptions
with default options.
This is equivalent to OpenOptions::new()
, but allows for more readable code.
§Examples
use atomic_write_file::AtomicWriteFile;
let file = AtomicWriteFile::options().read(true).open("foo.txt");
sourcepub fn as_file(&self) -> &File ⓘ
pub fn as_file(&self) -> &File ⓘ
Returns a reference to the underlaying File
struct.
The returned reference can be used to inspect or manipulate the contents and metadata of
this AtomicWriteFile
.
§Examples
use std::os::fd::AsRawFd;
use atomic_write_file::AtomicWriteFile;
let file = AtomicWriteFile::open("foo.txt")?;
assert_eq!(file.as_raw_fd(), file.as_file().as_raw_fd());
sourcepub fn as_file_mut(&mut self) -> &mut File ⓘ
pub fn as_file_mut(&mut self) -> &mut File ⓘ
Returns a mutable reference to the underlaying File
struct.
The returned reference can be used to inspect or manipulate the contents and metadata of
this AtomicWriteFile
.
§Examples
use std::io::Write;
use atomic_write_file::AtomicWriteFile;
let mut file = AtomicWriteFile::open("foo.txt")?;
writeln!(file.as_file_mut(), "hello")?;
sourcepub fn directory(&self) -> Option<Directory<'_>>
pub fn directory(&self) -> Option<Directory<'_>>
Returns a borrowed reference to the directory containing the file.
This method allows you to obtain the directory file descriptor, without having to open it
through a call to open(2)
. This method is guaranteed to make no system calls.
The returned struct supports only two operations:
- conversion to a borrowed directory file descriptor through
AsFd::as_fd()
- conversion to a raw directory file descriptor through
AsRawFd::as_raw_fd()
This method will return a result only if the platform supports directory file descriptors,
and if the AtomicWriteFile
implementation makes use of them. In all other cases, this
method returns None
.
§Examples
use std::os::fd::AsFd;
use atomic_write_file::AtomicWriteFile;
let file = AtomicWriteFile::open("foo.txt")?;
if let Some(dir) = file.directory() {
let borrowed_fd = dir.as_fd();
println!("directory fd: {:?}", borrowed_fd);
}
sourcepub fn commit(self) -> Result<()>
pub fn commit(self) -> Result<()>
Saves the contents of this file to its path.
After calling commit()
, the AtomicWriteFile
is consumed and can no longer be used.
Clones of the underlaying File
may still be used after calling commit()
, although any
write from that point onwards will no longer be atomic.
See the documentation for AtomicWriteFile
and the module-level documentation
for details about the internal implementation of commit()
, as well as platform-specific
details.
This method is automatically called when AtomicWriteFile
is dropped, although in that
case any error produced by commit()
is ignored.
See also AtomicWriteFile::discard()
.
§Examples
use std::io::Write;
use atomic_write_file::AtomicWriteFile;
let file = AtomicWriteFile::open("foo.txt")?;
writeln!(&file, "hello")?;
file.commit()?;
sourcepub fn discard(self) -> Result<()>
pub fn discard(self) -> Result<()>
Discard the contents of this file, and leave its path unchanged.
After calling discard()
, the AtomicWriteFile
is consumed and can no longer be used.
Clones of the underlaying File
may still be used after calling discard()
.
See also AtomicWriteFile::commit()
.
§Examples
use std::io::Write;
use atomic_write_file::AtomicWriteFile;
let file = AtomicWriteFile::open("foo.txt")?;
writeln!(&file, "hello")?;
file.discard()?;
Methods from Deref<Target = File>§
1.0.0 · sourcepub fn sync_all(&self) -> Result<(), Error>
pub fn sync_all(&self) -> Result<(), Error>
Attempts to sync all OS-internal file content and metadata to disk.
This function will attempt to ensure that all in-memory data reaches the filesystem before returning.
This can be used to handle errors that would otherwise only be caught
when the File
is closed, as dropping a File
will ignore all errors.
Note, however, that sync_all
is generally more expensive than closing
a file by dropping it, because the latter is not required to block until
the data has been written to the filesystem.
If synchronizing the metadata is not required, use sync_data
instead.
§Examples
use std::fs::File;
use std::io::prelude::*;
fn main() -> std::io::Result<()> {
let mut f = File::create("foo.txt")?;
f.write_all(b"Hello, world!")?;
f.sync_all()?;
Ok(())
}
1.0.0 · sourcepub fn sync_data(&self) -> Result<(), Error>
pub fn sync_data(&self) -> Result<(), Error>
This function is similar to sync_all
, except that it might not
synchronize file metadata to the filesystem.
This is intended for use cases that must synchronize content, but don’t need the metadata on disk. The goal of this method is to reduce disk operations.
Note that some platforms may simply implement this in terms of
sync_all
.
§Examples
use std::fs::File;
use std::io::prelude::*;
fn main() -> std::io::Result<()> {
let mut f = File::create("foo.txt")?;
f.write_all(b"Hello, world!")?;
f.sync_data()?;
Ok(())
}
1.0.0 · sourcepub fn set_len(&self, size: u64) -> Result<(), Error>
pub fn set_len(&self, size: u64) -> Result<(), Error>
Truncates or extends the underlying file, updating the size of
this file to become size
.
If the size
is less than the current file’s size, then the file will
be shrunk. If it is greater than the current file’s size, then the file
will be extended to size
and have all of the intermediate data filled
in with 0s.
The file’s cursor isn’t changed. In particular, if the cursor was at the end and the file is shrunk using this operation, the cursor will now be past the end.
§Errors
This function will return an error if the file is not opened for writing.
Also, std::io::ErrorKind::InvalidInput
will be returned if the desired length would cause an overflow due to
the implementation specifics.
§Examples
use std::fs::File;
fn main() -> std::io::Result<()> {
let mut f = File::create("foo.txt")?;
f.set_len(10)?;
Ok(())
}
Note that this method alters the content of the underlying file, even
though it takes &self
rather than &mut self
.
1.0.0 · sourcepub fn metadata(&self) -> Result<Metadata, Error>
pub fn metadata(&self) -> Result<Metadata, Error>
Queries metadata about the underlying file.
§Examples
use std::fs::File;
fn main() -> std::io::Result<()> {
let mut f = File::open("foo.txt")?;
let metadata = f.metadata()?;
Ok(())
}
1.9.0 · sourcepub fn try_clone(&self) -> Result<File, Error>
pub fn try_clone(&self) -> Result<File, Error>
Creates a new File
instance that shares the same underlying file handle
as the existing File
instance. Reads, writes, and seeks will affect
both File
instances simultaneously.
§Examples
Creates two handles for a file named foo.txt
:
use std::fs::File;
fn main() -> std::io::Result<()> {
let mut file = File::open("foo.txt")?;
let file_copy = file.try_clone()?;
Ok(())
}
Assuming there’s a file named foo.txt
with contents abcdef\n
, create
two handles, seek one of them, and read the remaining bytes from the
other handle:
use std::fs::File;
use std::io::SeekFrom;
use std::io::prelude::*;
fn main() -> std::io::Result<()> {
let mut file = File::open("foo.txt")?;
let mut file_copy = file.try_clone()?;
file.seek(SeekFrom::Start(3))?;
let mut contents = vec![];
file_copy.read_to_end(&mut contents)?;
assert_eq!(contents, b"def\n");
Ok(())
}
1.16.0 · sourcepub fn set_permissions(&self, perm: Permissions) -> Result<(), Error>
pub fn set_permissions(&self, perm: Permissions) -> Result<(), Error>
Changes the permissions on the underlying file.
§Platform-specific behavior
This function currently corresponds to the fchmod
function on Unix and
the SetFileInformationByHandle
function on Windows. Note that, this
may change in the future.
§Errors
This function will return an error if the user lacks permission change attributes on the underlying file. It may also return an error in other os-specific unspecified cases.
§Examples
fn main() -> std::io::Result<()> {
use std::fs::File;
let file = File::open("foo.txt")?;
let mut perms = file.metadata()?.permissions();
perms.set_readonly(true);
file.set_permissions(perms)?;
Ok(())
}
Note that this method alters the permissions of the underlying file,
even though it takes &self
rather than &mut self
.
1.75.0 · sourcepub fn set_times(&self, times: FileTimes) -> Result<(), Error>
pub fn set_times(&self, times: FileTimes) -> Result<(), Error>
Changes the timestamps of the underlying file.
§Platform-specific behavior
This function currently corresponds to the futimens
function on Unix (falling back to
futimes
on macOS before 10.13) and the SetFileTime
function on Windows. Note that this
may change in the future.
§Errors
This function will return an error if the user lacks permission to change timestamps on the underlying file. It may also return an error in other os-specific unspecified cases.
This function may return an error if the operating system lacks support to change one or
more of the timestamps set in the FileTimes
structure.
§Examples
fn main() -> std::io::Result<()> {
use std::fs::{self, File, FileTimes};
let src = fs::metadata("src")?;
let dest = File::options().write(true).open("dest")?;
let times = FileTimes::new()
.set_accessed(src.accessed()?)
.set_modified(src.modified()?);
dest.set_times(times)?;
Ok(())
}
1.75.0 · sourcepub fn set_modified(&self, time: SystemTime) -> Result<(), Error>
pub fn set_modified(&self, time: SystemTime) -> Result<(), Error>
Changes the modification time of the underlying file.
This is an alias for set_times(FileTimes::new().set_modified(time))
.
Trait Implementations§
source§impl AsFd for AtomicWriteFile
impl AsFd for AtomicWriteFile
source§fn as_fd(&self) -> BorrowedFd<'_>
fn as_fd(&self) -> BorrowedFd<'_>
source§impl AsRawFd for AtomicWriteFile
impl AsRawFd for AtomicWriteFile
source§impl Debug for AtomicWriteFile
impl Debug for AtomicWriteFile
source§impl Deref for AtomicWriteFile
impl Deref for AtomicWriteFile
source§impl DerefMut for AtomicWriteFile
impl DerefMut for AtomicWriteFile
source§impl Drop for AtomicWriteFile
impl Drop for AtomicWriteFile
source§impl FileExt for AtomicWriteFile
impl FileExt for AtomicWriteFile
source§fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize>
fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize>
source§fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize>
fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize>
source§fn read_exact_at(&self, buf: &mut [u8], offset: u64) -> Result<()>
fn read_exact_at(&self, buf: &mut [u8], offset: u64) -> Result<()>
buf
from the given offset. Read moresource§fn write_all_at(&self, buf: &[u8], offset: u64) -> Result<()>
fn write_all_at(&self, buf: &[u8], offset: u64) -> Result<()>
source§fn read_vectored_at(
&self,
bufs: &mut [IoSliceMut<'_>],
offset: u64,
) -> Result<usize, Error>
fn read_vectored_at( &self, bufs: &mut [IoSliceMut<'_>], offset: u64, ) -> Result<usize, Error>
unix_file_vectored_at
)read_at
, except that it reads into a slice of buffers. Read moresource§impl Read for &AtomicWriteFile
impl Read for &AtomicWriteFile
source§fn read(&mut self, buf: &mut [u8]) -> Result<usize>
fn read(&mut self, buf: &mut [u8]) -> Result<usize>
source§fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize>
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize>
read
, except that it reads into a slice of buffers. Read moresource§fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize>
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize>
buf
. Read moresource§fn read_to_string(&mut self, buf: &mut String) -> Result<usize>
fn read_to_string(&mut self, buf: &mut String) -> Result<usize>
buf
. Read moresource§fn read_exact(&mut self, buf: &mut [u8]) -> Result<()>
fn read_exact(&mut self, buf: &mut [u8]) -> Result<()>
buf
. Read moresource§fn is_read_vectored(&self) -> bool
fn is_read_vectored(&self) -> bool
can_vector
)source§fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<(), Error>
fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<(), Error>
read_buf
)source§fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> Result<(), Error>
fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> Result<(), Error>
read_buf
)cursor
. Read more1.0.0 · source§fn by_ref(&mut self) -> &mut Selfwhere
Self: Sized,
fn by_ref(&mut self) -> &mut Selfwhere
Self: Sized,
Read
. Read moresource§impl Read for AtomicWriteFile
impl Read for AtomicWriteFile
source§fn read(&mut self, buf: &mut [u8]) -> Result<usize>
fn read(&mut self, buf: &mut [u8]) -> Result<usize>
source§fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize>
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize>
read
, except that it reads into a slice of buffers. Read moresource§fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize>
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize>
buf
. Read moresource§fn read_to_string(&mut self, buf: &mut String) -> Result<usize>
fn read_to_string(&mut self, buf: &mut String) -> Result<usize>
buf
. Read moresource§fn read_exact(&mut self, buf: &mut [u8]) -> Result<()>
fn read_exact(&mut self, buf: &mut [u8]) -> Result<()>
buf
. Read moresource§fn is_read_vectored(&self) -> bool
fn is_read_vectored(&self) -> bool
can_vector
)source§fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<(), Error>
fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<(), Error>
read_buf
)source§fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> Result<(), Error>
fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> Result<(), Error>
read_buf
)cursor
. Read more1.0.0 · source§fn by_ref(&mut self) -> &mut Selfwhere
Self: Sized,
fn by_ref(&mut self) -> &mut Selfwhere
Self: Sized,
Read
. Read moresource§impl Seek for &AtomicWriteFile
impl Seek for &AtomicWriteFile
source§fn seek(&mut self, pos: SeekFrom) -> Result<u64>
fn seek(&mut self, pos: SeekFrom) -> Result<u64>
source§fn stream_position(&mut self) -> Result<u64>
fn stream_position(&mut self) -> Result<u64>
source§impl Seek for AtomicWriteFile
impl Seek for AtomicWriteFile
source§fn seek(&mut self, pos: SeekFrom) -> Result<u64>
fn seek(&mut self, pos: SeekFrom) -> Result<u64>
source§fn stream_position(&mut self) -> Result<u64>
fn stream_position(&mut self) -> Result<u64>
source§impl Write for &AtomicWriteFile
impl Write for &AtomicWriteFile
source§fn write(&mut self, buf: &[u8]) -> Result<usize>
fn write(&mut self, buf: &[u8]) -> Result<usize>
source§fn flush(&mut self) -> Result<()>
fn flush(&mut self) -> Result<()>
source§fn write_all(&mut self, buf: &[u8]) -> Result<()>
fn write_all(&mut self, buf: &[u8]) -> Result<()>
source§fn write_fmt(&mut self, fmt: Arguments<'_>) -> Result<()>
fn write_fmt(&mut self, fmt: Arguments<'_>) -> Result<()>
source§fn is_write_vectored(&self) -> bool
fn is_write_vectored(&self) -> bool
can_vector
)source§impl Write for AtomicWriteFile
impl Write for AtomicWriteFile
source§fn write(&mut self, buf: &[u8]) -> Result<usize>
fn write(&mut self, buf: &[u8]) -> Result<usize>
source§fn flush(&mut self) -> Result<()>
fn flush(&mut self) -> Result<()>
source§fn write_all(&mut self, buf: &[u8]) -> Result<()>
fn write_all(&mut self, buf: &[u8]) -> Result<()>
source§fn write_fmt(&mut self, fmt: Arguments<'_>) -> Result<()>
fn write_fmt(&mut self, fmt: Arguments<'_>) -> Result<()>
source§fn is_write_vectored(&self) -> bool
fn is_write_vectored(&self) -> bool
can_vector
)