std::path::Path / PathBuf
| Since: | Rust 1.0(2015) |
|---|
Rust uses std::path::Path and PathBuf for file path manipulation. Path is a borrowed, immutable path reference, while PathBuf is an owned, mutable path. Both automatically handle differences in path separators across operating systems.
Syntax
use std::path::{Path, PathBuf};
// Path — an immutable path reference (the path equivalent of &str)
let path = Path::new("/home/user/file.txt");
// PathBuf — an owned, mutable path (the path equivalent of String)
let mut buf = PathBuf::from("/home/user");
buf.push("documents"); // Appends a component to the path.
buf.push("file.txt");
// Joining paths (join returns a new PathBuf)
let full = Path::new("/home").join("user").join("file.txt");
// Retrieving path information
path.file_name() // "file.txt"
path.file_stem() // "file" (without extension)
path.extension() // "txt"
path.parent() // "/home/user"
path.exists() // Checks whether the file exists.
path.is_file() // Checks whether this is a file.
path.is_dir() // Checks whether this is a directory.
Method List
| Method | Description |
|---|---|
| Path::new(s) | Creates a Path reference from a string. |
| PathBuf::from(s) | Creates a PathBuf from a string. |
| path.join(p) | Returns a new PathBuf with the given component appended. |
| buf.push(p) | Appends a component to a PathBuf in place (mutable). |
| path.exists() | Returns true if the path exists on the filesystem. |
| path.is_file() | Returns true if the path points to a regular file. |
| path.is_dir() | Returns true if the path points to a directory. |
| path.file_name() | Returns the final component of the path as Option<&OsStr>. |
| path.file_stem() | Returns the file name without its extension. |
| path.extension() | Returns the file extension as Option<&OsStr>. |
| path.parent() | Returns the parent directory as Option<&Path>. |
| path.to_str() | Converts the path to &str (returns None if not valid UTF-8). |
| path.display() | Returns a display-friendly string representation (usable with println!). |
Sample Code
sample_path_pathbuf.rs
use std::path::{Path, PathBuf};
use std::fs;
fn main() {
// Build a path using PathBuf.
let mut path = PathBuf::from("/home");
path.push("user");
path.push("documents");
path.push("report.txt");
println!("path: {}", path.display());
// /home/user/documents/report.txt
// Join paths using join (the original path is unchanged).
let base = Path::new("/var/log");
let app_log = base.join("myapp").join("error.log");
println!("app_log: {}", app_log.display());
// /var/log/myapp/error.log
// Retrieve individual components of a path.
let file = Path::new("/home/user/documents/report.txt");
println!("file_name: {:?}", file.file_name()); // "report.txt"
println!("file_stem: {:?}", file.file_stem()); // "report"
println!("extension: {:?}", file.extension()); // "txt"
println!("parent: {:?}", file.parent()); // "/home/user/documents"
// Check existence and type.
let current = Path::new(".");
println!("current directory exists: {}", current.exists()); // true
println!("is_dir: {}", current.is_dir()); // true
println!("is_file: {}", current.is_file()); // false
// Convert to &str.
if let Some(s) = file.to_str() {
println!("to_str: {}", s);
}
let test_path = Path::new("test_path.txt");
fs::write(test_path, "test").unwrap();
println!("test_path exists: {}", test_path.exists()); // true
println!("test_path is_file: {}", test_path.is_file()); // true
fs::remove_file(test_path).unwrap();
// Change the extension (PathBuf only).
let mut p = PathBuf::from("archive.tar.gz");
p.set_extension("bz2");
println!("after change: {}", p.display()); // archive.tar.bz2
// Iterate over path components.
for component in Path::new("/home/user/file.txt").components() {
println!("component: {:?}", component);
}
}
Compile with the following command:
rustc sample_path_pathbuf.rs
./sample_path_pathbuf
path: /home/user/documents/report.txt
app_log: /var/log/myapp/error.log
file_name: Some("report.txt")
file_stem: Some("report")
extension: Some("txt")
parent: Some("/home/user/documents")
current directory exists: true
is_dir: true
is_file: false
to_str: /home/user/documents/report.txt
test_path exists: true
test_path is_file: true
after change: archive.tar.bz2
component: RootDir
component: Normal("home")
component: Normal("user")
component: Normal("file.txt")
Common Mistakes
Common mistake 1: building paths with string concatenation
Concatenating strings with '/' to build paths can cause problems with OS-specific separators or double slashes. Use PathBuf and push() or join() instead.
let path = "/home/".to_string() + "user/" + "file.txt";
The same logic can also be written as:
use std::path::PathBuf;
let mut path = PathBuf::from("/home");
path.push("user");
path.push("file.txt");
println!("{}", path.display()); // /home/user/file.txt
Common mistake 2: unwrapping to_str() unconditionally
to_str() returns None when the path is not valid UTF-8. Calling unwrap() directly will panic on non-UTF-8 paths.
use std::path::Path;
// Panics on non-UTF-8 paths
let path = Path::new("/home/kiryu/file.txt");
let s = path.to_str().unwrap();
The same logic can also be written as:
use std::path::Path;
// Safe: handle the Option explicitly
let path = Path::new("/home/kiryu/file.txt");
match path.to_str() {
Some(s) => println!("path: {}", s),
None => println!("path is not valid UTF-8"),
}
// Or use display() which works for any path
println!("{}", path.display());
Common mistake 3: confusing Path and PathBuf ownership
Path is a borrowed reference (like &str) and cannot be stored in a struct without a lifetime. Use PathBuf (like String) when you need ownership.
use std::path::Path;
// Compile error: cannot store a borrowed Path without a lifetime annotation
// struct Config {
// path: Path, // error: the size of `Path` cannot be known at compile-time
// }
The same logic can also be written as:
use std::path::PathBuf;
// Correct: use PathBuf for owned paths in structs
struct Config {
path: PathBuf,
}
let config = Config {
path: PathBuf::from("/home/kiryu/config.toml"),
};
println!("{}", config.path.display());
Notes
The relationship between Path and PathBuf mirrors the relationship between &str and String. Function parameters typically accept &Path or impl AsRef<Path>, allowing string literals, PathBuf, and other types to be passed interchangeably.
On Windows the path separator is \, and on Unix-like systems it is /. Rust's Path automatically uses the appropriate separator for the target OS, making it straightforward to write cross-platform code.
For reading and writing files, see std::fs::read_to_string() / write(). For fine-grained control using file handles, see File::open() / File::create().
If you find any errors or copyright issues, please contact us.