Traversing directories is a fundamental operation when working with filesystems. Whether you're building a file search tool, calculating disk usage, or processing batches of files, you need to navigate directory trees efficiently. Rust's std::fs module provides read_dir() for listing directory contents and metadata() for inspecting file properties.
The std::fs::read_dir() function returns an iterator over directory entries:
use std::fs;
for entry in fs::read_dir("./src")? {
let entry = entry?;
let path = entry.path();
println!("{}", path.display());
}Each DirEntry provides access to the file's path, name, metadata, and file type without additional system calls for basic information.
To traverse subdirectories, you need to implement recursion yourself. Check if each entry is a directory using entry.file_type()?.is_dir() and recurse into it:
fn visit_dirs(dir: &Path) -> io::Result<()> {
for entry in fs::read_dir(dir)? {
let entry = entry?;
let path = entry.path();
if path.is_dir() {
// Recurse into subdirectory
visit_dirs(&path)?;
} else {
println!("File: {}", path.display());
}
}
Ok(())
}You can filter entries by extension, name pattern, or other criteria as you iterate:
for entry in fs::read_dir(".")? {
let path = entry?.path();
if path.extension().map_or(false, |ext| ext == "rs") {
println!("Rust file: {}", path.display());
}
}Implement the following directory traversal functions:
list_files(dir: &Path) -> io::Result<Vec<PathBuf>>
list_directories(dir: &Path) -> io::Result<Vec<PathBuf>>
list_all_recursive( dir: &Path ) -> io::Result<Vec<PathBuf>>
find_by_extension( dir: &Path, ext: &str ) -> io::Result<Vec<PathBuf>>
find_by_name( dir: &Path, name: &str ) -> io::Result<Vec<PathBuf>>
calculate_dir_size(dir: &Path) -> io::Result<u64>
count_files_recursive( dir: &Path ) -> io::Result<usize>
use std::path::Path;
// List only files in a directory
// (not subdirectories or their contents)
let files = list_files(Path::new("./src"))?;
// Returns: ["./src/main.rs", "./src/lib.rs"]
// List only immediate subdirectories
let dirs = list_directories(Path::new("./project"))?;
// Returns: ["./project/src", "./project/tests"]
// Recursively list everything
let all = list_all_recursive(Path::new("./src"))?;
// Returns all files and directories at all levels
// Find all Rust source files
let rust_files = find_by_extension(Path::new("./"), "rs")?;
// Returns all .rs files recursively
// Find files or directories named "Cargo.toml"
let cargo_files = find_by_name(
Path::new("./"),
"Cargo.toml"
)?;
// Returns all paths ending in "Cargo.toml"
// Calculate total size of a directory
let size = calculate_dir_size(Path::new("./src"))?;
// Returns total bytes of all files
// Count files in directory tree
let count = count_files_recursive(Path::new("./src"))?;
// Returns number of files (not directories)std::fs::read_dir(path) to get an
iterator over directory entriesread_dir() is a
Result<DirEntry, io::Error> - handle errors
with ?entry.path() to get the full PathBuf
for an entryentry.file_type()?.is_dir() or
entry.path().is_dir() to check if it's a
directoryentry.metadata()?.len() to get the file
size in bytespath.extension().map_or( false, |e| e == ext )path.file_name().map_or( false, |n| n == name )read_dir() only lists
immediate children, not nested contents