Rust Editing Paths
Path editing changes a path value into a new path. Editing can swap the file name.
Change the ending on a copy
with_extension builds a new path. The old one is untouched:
let p = Path::new("notes.txt").with_extension("md");
println!("{}", p.display());Change a PathBuf in place
set_extension edits the buffer itself. An empty ending removes the dot and the ending:
let mut p = PathBuf::from("report.txt");
p.set_extension("csv");
println!("{}", p.display());
p.set_extension("");
println!("{}", p.display());Only the last dot counts
A name can hold several dots. Rust splits at the last one:
let p = Path::new("archive.tar.gz");
println!("stem = {}", p.file_stem().unwrap().to_string_lossy());
println!("ext = {}", p.extension().unwrap().to_string_lossy());
println!("zipped = {}", p.with_extension("zip").display());Swap the name, keep the folder
with_file_name replaces the last piece only:
let p = Path::new("reports/2026/sales.txt").with_file_name("summary.csv");
println!("{}", p.display());Names are OsStr, not text
file_name() gives an &OsStr. to_str() is Some only when the name is valid UTF-8:
let name = Path::new("data.bin").file_name().unwrap();
println!("as text = {:?}", name.to_str());
println!("printed = {}", name.to_string_lossy());Example
use std::path::Path;
fn main() {
let path = Path::new("reports/2026/sales.txt");
println!("start = {}", path.display());
println!("as csv = {}", path.with_extension("csv").display());
println!("renamed = {}", path.with_file_name("summary.txt").display());
let mut owned = path.to_path_buf();
owned.set_extension("bak");
println!("backup = {}", owned.display());
owned.set_extension("");
println!("no ending = {}", owned.display());
}Key points
- Use path.with_extension("md") to get a copy of the path with a new ending: the original path is unchanged
- Use path_buf.set_extension("md") to change a PathBuf in place: set_extension("") removes the ending
- Use with_file_name(name) to swap only the last piece: the folders stay the same
- Only the last dot counts: the stem of archive.tar.gz is archive.tar, and its extension is gz
- A leading dot is part of the name, not an ending: .gitignore has no extension
- Path editing makes a new path from an old one by changing its name or its ending.
In this example, no file moves on disk. Only path values change. with_extension and with_file_name each build a fresh path. The original stays reports/2026/sales.txt. to_path_buf then makes an owned copy. set_extension edits that copy in place. It first swaps txt for bak. Then it removes the ending for good.
Note
file_name() returns an &OsStr, not text.
A name can hold bytes that are not valid UTF-8.
So to_str() returns an Option.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Rust Playground
Exercise
What is the extension of archive.tar.gz?