Creating temporary files in Rust is sometimes essential when we need to use the files once or cache data for a short time. We then let the operating system delete the files at a later time automatically or by its clean-up feature manually.
Operating System Temporary Directory
To benefit from the auto-deletion, we must create temporary files in directories the operating system looks for files to delete. Hence, we need to get the temp directory. In Rust, we can use the temp_dir ( std::env::temp_dir) function to that end.
1 2 3 4 5 6 7 8 | use std::env::temp_dir; use std::io::Result; fn main() -> Result<()> { let dir = temp_dir(); println!("{}", dir.to_str().unwrap()); Ok(()) } |
The codes generate the following output.
1 2 3 4 5 6 7 | C:/Users/karldev/.cargo/bin/cargo.exe run --color=always --package create-temporary-files --bin create-temporary-files Compiling create-temporary-files v0.1.0 (C:\Users\karldev\Desktop\dev\blogs\rust\create-temporary-files) Finished dev [unoptimized + debuginfo] target(s) in 0.48s Running `target\debug\create-temporary-files.exe` C:\Users\karldev\AppData\Local\Temp\ Process finished with exit code 0 |
For Unix, the temp_dir function returns directory specified for the TMPDIR environment. Otherwise, it returns /tmp. For Android operating system, the temp_dir function returns /data/local/tmp.
For Windows, the function works a little bit differently. The function first checks the TMP environment for value. If TMP is empty, it then checks the TEMP environment. When TEMP is empty or undefined, the function then checks the USERPROFILE environment. If USERPROFILE is still undefined, the function returns the Windows directory.
Create Temporary Files in Rust
Temporary files typically have unique names to ensure that our codes refer to a file it had created and used at a particular instance. We could use UUIDs as file names.
In the Cargo.toml, update the dependencies as follows.
1 2 3 4 5 6 7 8 | [package] name = "create-temporary-files" version = "0.1.0" authors = ["Karl San Gabriel"] edition = "2018" [dependencies] uuid = { version = "0.8.1", features = ["serde", "v4"] } |
Then, we can use to generate UUIDs.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | use std::env::temp_dir; use std::io::Result; use uuid::Uuid; use std::fs::File; fn main() -> Result<()> { let mut dir = temp_dir(); println!("{}", dir.to_str().unwrap()); let file_name = format!("{}.txt", Uuid::new_v4()); println!("{}", file_name); dir.push(file_name); let file = File::create(dir)?; Ok(()) } |
When we run the codes, we get the following output.
1 2 3 4 5 6 7 8 | C:/Users/karldev/.cargo/bin/cargo.exe run --color=always --package create-temporary-files --bin create-temporary-files Compiling create-temporary-files v0.1.0 (C:\Users\karldev\Desktop\dev\blogs\rust\create-temporary-files) Finished dev [unoptimized + debuginfo] target(s) in 0.80s Running `target\debug\create-temporary-files.exe` C:\Users\karldev\AppData\Local\Temp\ f18033e3-5d28-4065-8bde-ae75eb6d9b6f.txt Process finished with exit code 0 |
We can then verify the codes generated a file with the same name.
Using the tempfile crate
In case we do not want to reinvent the wheels, there is a crate available for creating temporary files and even directories. The tempfile crate has the following functions and structs for dealing with temporary files and directories.
To use the crate, update Cargo.toml as follows.
1 2 3 4 5 6 7 8 | [package] name = "create-temporary-files" version = "0.1.0" authors = ["Karl San Gabriel"] edition = "2018" [dependencies] tempfile = "3.1.0" |
The tempfile() and tempdir() functions create files and directories and rely on the underlying operating system to remove them when handles close. The following codes create a temporary file and a temporary directory.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | use tempfile::tempfile; use tempfile::tempdir; use std::io::Result; use std::io::Write; fn main() -> Result<()> { // Create a temporary file inside of the directory returned by `std::env::temp_dir()`. let mut temp_file = tempfile()?; write!(temp_file, "This is a temp file")?; println!("{:?}", temp_file); // Create a temporary dir inside of the directory returned by `std::env::temp_dir()`. let temp_dir = tempdir()?; println!("{:?}", temp_dir); Ok(()) } |
We get the following output.
1 2 3 4 5 6 7 | C:/Users/karldev/.cargo/bin/cargo.exe run --color=always --package create-temporary-files --bin create-temporary-files Finished dev [unoptimized + debuginfo] target(s) in 0.07s Running `target\debug\create-temporary-files.exe` File { handle: 0xa0, path: "\\\\?\\C:\\Users\\karldev\\AppData\\Local\\Temp\\.tmph6YSB6" } TempDir { path: "C:\\Users\\karldev\\AppData\\Local\\Temp\\.tmpUpHaRG" } Process finished with exit code 0 |
We will not be able to see the files and directories when the application completes execution. The operating system deletes them when the handles close.
The structs NamedTempFile and TempDir work the same way but require explicit deletion via their destructors. Consider the following codes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | use tempfile::{NamedTempFile, TempDir}; use std::io::Result; use std::io::Write; fn main() -> Result<()> { // Create a temporary file inside of the directory returned by `std::env::temp_dir()`. let mut temp_file = NamedTempFile::new()?; write!(temp_file, "This is a temp file")?; println!("{:?}", temp_file); // Create a temporary dir inside of the directory returned by `std::env::temp_dir()`. let temp_dir = TempDir::new()?; println!("{:?}", temp_dir); temp_file.close()?; temp_dir.close()?; Ok(()) } |
The output is as follows.
1 2 3 4 5 6 7 8 | C:/Users/karldev/.cargo/bin/cargo.exe run --color=always --package create-temporary-files --bin create-temporary-files Compiling create-temporary-files v0.1.0 (C:\Users\karldev\Desktop\dev\blogs\rust\create-temporary-files) Finished dev [unoptimized + debuginfo] target(s) in 0.76s Running `target\debug\create-temporary-files.exe` NamedTempFile("C:\\Users\\karldev\\AppData\\Local\\Temp\\.tmpeP0U6q") TempDir { path: "C:\\Users\\karldev\\AppData\\Local\\Temp\\.tmpISikix" } Process finished with exit code 0 |