File.create()
std::fs::File::create(path) opens a file in write-only mode, creating the file if it does not exist and immediately truncating its length to 0 bytes if it already exists. It is a shorthand for OpenOptions::new().write(true).create(true).truncate(true).open(path).
Comparing File::create, File::create_new, and OpenOptions::append
Because File::create(path) silently wipes out any existing file at path, Rust also provides File::create_new(path) (stabilized in Rust 1.77), which atomically creates a new file and fails with ErrorKind::AlreadyExists if a file or symlink already exists at path:
| Method | Mode | If File Does NOT Exist | If File ALREADY Exists |
|---|---|---|---|
File::create(path) |
Write-only | Creates new file | Truncates existing file to 0 bytes! |
File::create_new(path) |
Read + Write | Atomically creates new file | Fails with ErrorKind::AlreadyExists (never overwrites!) |
File::options().append(true).open(path) |
Append | Fails with NotFound (unless .create(true) added) |
Preserves existing bytes and appends at end |
Danger of `File::create` vs. Safety of `File::create_new`:
`File::create("important.db")` ---> Overwrites and zeroes out existing `important.db`!
`File::create_new("important.db")` ---> Uses OS `O_CREAT | O_EXCL`: atomic check-and-create,
returns `Err(AlreadyExists)` if file is present!
use std::fs::{self, File};
use std::io::{self, ErrorKind, Write};
fn main() -> io::Result<()> {
let path = std::env::temp_dir().join("rust_ch50_create_demo.txt");
let _ = fs::remove_file(&path);
// 1. `File::create_new` succeeds when the file does not exist yet:
{
let mut f = File::create_new(&path)?;
f.write_all(b"initial important data\n")?;
}
// 2. A second `File::create_new` on the same path fails with `AlreadyExists`
// without harming the existing file!
match File::create_new(&path) {
Ok(_) => unreachable!("file already exists"),
Err(e) if e.kind() == ErrorKind::AlreadyExists => {
println!("create_new prevented accidental overwrite (AlreadyExists)");
}
Err(e) => return Err(e),
}
// 3. `File::create` truncates and replaces the existing file:
{
let mut f = File::create(&path)?;
f.write_all(b"replaced\n")?;
}
let final_text = fs::read_to_string(&path)?;
fs::remove_file(&path)?;
print!("final content after File::create: {}", final_text);
Ok(())
}
create_new prevented accidental overwrite (AlreadyExists)
final content after File::create: replaced
Parent Directory Must Exist
Neither File::create nor File::create_new automatically creates missing parent directories. If "output/reports/q1.csv" is passed to File::create and "output/reports" does not exist yet, File::create returns Err(ErrorKind::NotFound). Call if let Some(parent) = path.parent() { fs::create_dir_all(parent)?; } first when writing to a nested directory path.