Skip to main content

NamedTempFile

Struct NamedTempFile 

Source
pub struct NamedTempFile { /* private fields */ }
Expand description

A temporary file that auto-deletes when dropped.

Companion to crate::TempDir. Where TempDir manages a directory, NamedTempFile manages a single zero-byte file at a fresh path under the OS temp location. The caller reopens the path with std::fs::OpenOptions (or any other API) when ready to write or read.

The default basename is .tmpfile-{pid}-{name12}, intentionally distinct from TempDir’s .tmp-{pid}-{name12} so an operator inspecting the OS temp location can tell the two apart at a glance. The 12 trailing characters use the same Crockford base32 generator as TempDir, so the optional mod-rand feature controls both types in lockstep. The embedded PID lets cleanup_orphans identify files left behind by crashed processes.

§Example

use mod_tempdir::NamedTempFile;
use std::io::Write;

let f = NamedTempFile::new().unwrap();
let mut handle = std::fs::OpenOptions::new()
    .write(true)
    .open(f.path())
    .unwrap();
handle.write_all(b"hello").unwrap();
drop(handle);
// `f` is deleted automatically when it goes out of scope.

§Cleanup semantics

Drop calls std::fs::remove_file best-effort. A failure (file already gone, permission denied, or a still-open handle on Windows) is intentionally swallowed: a Drop impl must not panic. Use NamedTempFile::persist to keep the file alive past drop.

§Windows handle-lock caveat

On Windows, std::fs::remove_file returns ERROR_SHARING_VIOLATION (surfaced in Rust as std::io::ErrorKind::PermissionDenied) if any process still holds an open handle to the file at the moment of Drop. The library does not retry. Drop must not block, and retries cannot force-close a caller-owned handle. The file is left on disk in that case. Close any handles you open against NamedTempFile::path before the NamedTempFile drops to guarantee cleanup.

Implementations§

Source§

impl NamedTempFile

Source

pub fn new() -> Result<Self>

Create a new temporary file in the system’s temp location (/tmp on Linux/macOS, %TEMP% on Windows).

The basename is .tmpfile-{pid}-{name12} where {pid} is the current process ID (used by cleanup_orphans to identify entries left behind by crashed processes) and {name12} is a 12-character Crockford base32 string from the shared name generator. The file is materialized via std::fs::File::create; the returned File handle is closed before this function returns, so the caller starts from a clean slate.

With the mod-rand feature enabled, the name fragment comes from mod_rand::tier2::unique_name. Without it, from the same internal process-unique mixer as TempDir::new.

§Errors

Returns the underlying io::Error from std::fs::File::create if the file cannot be created.

§Example
use mod_tempdir::NamedTempFile;

let f = NamedTempFile::new().unwrap();
assert!(f.path().is_file());
Source

pub fn with_prefix(prefix: &str) -> Result<Self>

Create a new temporary file with the given prefix.

The final basename is {prefix}-{12-char-name}. The prefix is joined verbatim and is the caller’s responsibility to sanitize.

§Errors

Returns the underlying io::Error from std::fs::File::create if the file cannot be created.

§Example
use mod_tempdir::NamedTempFile;

let f = NamedTempFile::with_prefix("my-fixture").unwrap();
assert!(f
    .path()
    .file_name()
    .unwrap()
    .to_string_lossy()
    .starts_with("my-fixture-"));
Source

pub fn path(&self) -> &Path

Return the path of this temporary file.

§Example
use mod_tempdir::NamedTempFile;

let f = NamedTempFile::new().unwrap();
let mut handle = std::fs::OpenOptions::new()
    .write(true)
    .open(f.path())
    .unwrap();
Source

pub fn persist(self) -> PathBuf

Consume this NamedTempFile and return the path, disabling cleanup on drop. The file will persist.

Use this when you want to inspect contents after a test fails.

§Example
use mod_tempdir::NamedTempFile;

let f = NamedTempFile::new().unwrap();
let kept = f.persist();
// `kept` survives past the original `f` going out of scope.
Source

pub fn cleanup_on_drop(&self) -> bool

Return true if the file will be deleted on drop.

§Example
use mod_tempdir::NamedTempFile;

let f = NamedTempFile::new().unwrap();
assert!(f.cleanup_on_drop());
Source

pub fn persist_atomic( self, target: impl AsRef<Path>, ) -> Result<PathBuf, PersistAtomicError>

Atomically move this file to target with crash-safety guarantees, then disable cleanup on drop.

Performs the canonical “atomic durable write” sequence:

  1. fsync the temp file contents to disk (std::fs::File::sync_all).
  2. Atomically rename the temp file onto target via std::fs::rename. On Unix this is rename(2); on Windows it is MoveFileExW with MOVEFILE_REPLACE_EXISTING. Both are atomic within a single filesystem.
  3. Best-effort fsync of the target’s parent directory so the rename itself survives a crash. Failures here are silent, matching the rest of the crate’s durability story.

On success, the temp file no longer exists at path; the data lives at target. Cleanup on drop is disabled and the consumed self does not attempt removal.

§Errors

On any failure (fsync, rename, etc.), the temp file is preserved on disk and returned to the caller via PersistAtomicError::file. The caller can inspect the underlying io::Error, optionally fix the cause (e.g., create the missing parent directory), and retry. This is the standard tempfile-crate pattern and matches the data-integrity guarantee that a failed atomic-persist must never lose the source.

Common error causes:

  • Target’s parent directory does not exist.
  • Target’s parent is on a different filesystem (EXDEV on Unix, ERROR_NOT_SAME_DEVICE on Windows).
  • Permission denied at the target location.
  • Source temp file already removed (race with cleanup).
§Cross-filesystem behaviour

rename is atomic only within a single filesystem. If target is on a different mount than the temp directory, rename will return EXDEV on Unix or the equivalent on Windows. Callers wanting cross-filesystem persistence must either pick a target on the same filesystem as std::env::temp_dir or do their own copy-and-delete.

§Example
use mod_tempdir::NamedTempFile;
use std::io::Write;

let f = NamedTempFile::new().unwrap();
{
    let mut h = std::fs::OpenOptions::new()
        .write(true)
        .open(f.path())
        .unwrap();
    h.write_all(b"finalized payload").unwrap();
}

let target = std::env::temp_dir().join("finalized.bin");
let landed = f.persist_atomic(&target).unwrap();
assert_eq!(landed, target);

Retry pattern on recoverable error:

use mod_tempdir::NamedTempFile;

let mut f = NamedTempFile::new().unwrap();
let target = std::env::temp_dir().join("retry-target");
loop {
    match f.persist_atomic(&target) {
        Ok(_landed) => break,
        Err(e) => {
            eprintln!("persist failed: {}", e.error);
            // ... fix the underlying issue ...
            f = e.file; // recover the temp file and try again
        }
    }
}

Trait Implementations§

Source§

impl Debug for NamedTempFile

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Drop for NamedTempFile

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.