Directory Traversal
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.
Reading Directory Contents
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.
Recursive Traversal
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(())
}Filtering Files
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());
}
}Your Task
Implement the following directory traversal functions:
list_files(dir: &Path) -> io::Result<Vec<PathBuf>>- List all files (not directories) in a directory (non-recursive)
list_directories(dir: &Path) -> io::Result<Vec<PathBuf>>- List all subdirectories in a directory (non-recursive)
list_all_recursive( dir: &Path ) -> io::Result<Vec<PathBuf>>- Recursively list all files and directories
find_by_extension( dir: &Path, ext: &str ) -> io::Result<Vec<PathBuf>>- Find all files with a given extension (recursive)
find_by_name( dir: &Path, name: &str ) -> io::Result<Vec<PathBuf>>- Find all files/directories matching a name exactly (recursive)
calculate_dir_size(dir: &Path) -> io::Result<u64>- Calculate total size of all files in a directory (recursive)
count_files_recursive( dir: &Path ) -> io::Result<usize>- Count all files in a directory tree
Examples
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)Hints
Click here for hints
- Use
std::fs::read_dir(path)to get an iterator over directory entries - Each entry from
read_dir()is aResult<DirEntry, io::Error>- handle errors with? - Use
entry.path()to get the fullPathBuffor an entry - Use
entry.file_type()?.is_dir()orentry.path().is_dir()to check if it's a directory - For recursive functions, call the function on subdirectories and combine results
- Use
entry.metadata()?.len()to get the file size in bytes - For extension matching, use
path.extension().map_or( false, |e| e == ext ) - For name matching, use
path.file_name().map_or( false, |n| n == name ) - Remember that
read_dir()only lists immediate children, not nested contents
Run to execute your code and see test results here.