🎓 A1Learner
🔍

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?