🎓 A1Learner
🔍

Rust Temporary Files

Temporary files are scratch files a program uses for a short job. The standard library can build these scratch files on its own.

Where scratch files live

temp_dir() asks the system. The answer is always an absolute path:

let dir = std::env::temp_dir();
println!("temp is absolute = {}", dir.is_absolute());

A name nobody else picked

Put your process id in the name. No other running program has the same id:

let path = std::env::temp_dir().join(format!("mytool-{}.tmp", std::process::id()));
println!("in temp = {}", path.starts_with(std::env::temp_dir()));

Create it only if it is free

create_new(true) refuses a taken name. It answers AlreadyExists instead of overwriting:

let first = OpenOptions::new().write(true).create_new(true).open("scratch.tmp");
println!("first try ok = {}", first.is_ok());
let second = OpenOptions::new().write(true).create_new(true).open("scratch.tmp");
println!("second try kind = {:?}", second.unwrap_err().kind());

Write temp, then rename over

The rename swaps the finished file into place in one step:

fs::write("data.tmp", "new version")?;
fs::rename("data.tmp", "data.txt")?;
println!("{}", fs::read_to_string("data.txt")?);

A scratch folder of your own

A whole folder works too. Build it, use it, then remove the whole tree:

let dir = Path::new("scratchpad");
fs::create_dir_all(dir)?;
fs::write(dir.join("a.txt"), "x")?;
println!("files inside = {}", fs::read_dir(dir)?.count());
fs::remove_dir_all(dir)?;
println!("gone = {}", !dir.exists());

Example

use std::fs::{self, OpenOptions};
use std::io::Write;

fn main() {
    // the old saved version
    fs::write("config.txt", "version 1").expect("could not write the old config");

    // save the new version beside it, then rename it over in one step
    let tmp = "config.txt.tmp";
    fs::write(tmp, "version 2").expect("could not write the temp file");
    fs::rename(tmp, "config.txt").expect("could not rename over");
    println!("saved = {}", fs::read_to_string("config.txt").expect("could not read back"));
    println!("temp left = {}", std::path::Path::new(tmp).exists());

    // a scratch file in the system temp folder, named with our process id
    let scratch = std::env::temp_dir().join(format!("mytool-{}.tmp", std::process::id()));
    let mut file = OpenOptions::new().write(true).create_new(true).open(&scratch)
        .expect("could not create the scratch file");
    write!(file, "scratch").expect("could not write the scratch file");
    drop(file);
    println!("scratch bytes = {}", fs::metadata(&scratch).expect("no metadata").len());
    fs::remove_file(&scratch).expect("could not remove the scratch file");
    println!("scratch cleaned = {}", !scratch.exists());

    fs::remove_file("config.txt").expect("could not clean up");
}

Key points

  • A temporary file is scratch space that a program removes when the job is done.
  • Use std::env::temp_dir() to find the folder the system keeps scratch files in
  • Make the name unique before you create the file: your process id is a number no other running program shares
  • Use OpenOptions with create_new(true) to create a file only when the name is still free.
  • The call fails instead of replacing a stranger's file
  • Write to a temp file first.
  • Then rename it over the real file.
  • A crash mid-write leaves the old real file untouched
  • Clean up after yourself: remove the temp file or folder when the job is done

In this example, the program saves a config in the safe order. It writes version 2 to a temp name first. Then one rename swaps it over version 1. No half-written config ever exists. The second half makes a scratch file in the system temp folder. Its name carries the process id. create_new proves the name was free. The program writes seven bytes, measures them, and removes the file again.

Note

The tempfile crate automates all of this.

Its files delete themselves when dropped.

It also picks names that cannot collide.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Rust Playground

Exercise

Why write to a temp file and rename, instead of writing the real file directly?