Rust Paths
Path and PathBuf are Rust's types for file paths. A path names a file, like "story.txt".
Build a path piece by piece
push(part) extends a PathBuf in place, one piece at a time:
let mut path = PathBuf::from("reports");
path.push("2026");
path.push("sales.txt");
println!("{}", path.display());Join in one call
join adds one piece with the separator this computer uses — never glue pieces together with / or \ by hand:
let path = Path::new("reports").join("sales.txt");
println!("{}", path.display());Take a path apart
file_name() gives the last piece. parent() gives everything before it. extension() gives the part after the final dot. And file_stem() gives the name without its extension. display() prints a path. to_str() — when you truly need text — returns an Option. The name might not be UTF-8. to_string_lossy() is the forgiving printer used here:
let path = Path::new("reports/2026/sales.txt");
println!("name = {}", path.file_name().unwrap().to_string_lossy());
println!("stem = {}", path.file_stem().unwrap().to_string_lossy());
println!("ext = {}", path.extension().unwrap().to_string_lossy());
println!("parent = {}", path.parent().unwrap().display());Take the last piece back off
pop() removes the piece that push added last:
let mut path = PathBuf::from("reports/2026/sales.txt");
path.pop();
println!("{}", path.display());Ask where the program is running
env::current_dir() gives the folder the program is running from, as a PathBuf. It returns a Result, because the folder could have been deleted. env::set_current_dir(path) moves the program to a different folder:
let here = env::current_dir().unwrap();Take a path as a parameter
A function can take impl AsRef<Path> as its parameter type. One signature then accepts text, a &Path, or a PathBuf. Callers pass what they already have:
fn name_of(path: impl AsRef<Path>) -> String {
let path = path.as_ref();
path.file_name().unwrap().to_string_lossy().into_owned()
}
println!("{}", name_of("reports/sales.txt"));
println!("{}", name_of(PathBuf::from("data.bin")));Example
use std::path::PathBuf;
fn main() {
let mut path = PathBuf::from("reports");
path.push("2026");
path.push("sales.txt");
println!("full = {}", path.display());
println!("name = {}", path.file_name().unwrap().to_string_lossy());
println!("stem = {}", path.file_stem().unwrap().to_string_lossy());
println!("ext = {}", path.extension().unwrap().to_string_lossy());
println!("parent = {}", path.parent().unwrap().display());
}Key points
- Use std::path::Path for a borrowed path and std::path::PathBuf for an owned one — the same pairing as &str and String
- A Path is not plain text inside.
- It is stored as an OsString.
- So it can hold file names that are not valid UTF-8 text.
- Use &Path or impl AsRef<Path> for path parameters.
- One function then accepts text, Path, and PathBuf arguments alike.
- Plain file names use the same current-folder rule.
In this example, the program runs on a Linux or Mac terminal, where the separator is /. PathBuf::from("reports") starts an owned path holding one piece. push adds 2026, then sales.txt — each push uses the right separator by itself. file_name() picks out the last piece, sales.txt. file_stem() drops the ending, giving sales, and extension() keeps only the ending, txt. parent() gives everything before the name: reports/2026. On Windows the same code prints backslashes instead — the pieces and answers stay the same.
Note
Path::new(".") means the folder the program runs from.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Rust Playground
Exercise
What does extension() return for the path reports/sales.txt?