Directory Traversal
File names that have been modified in the last 24 hours
Gets the current working directory and returns file names modified within the last 24 hours.env::current_dir
gets the current working directory,WalkDir::new
creates a newWalkDir
for the current directory.WalkDir::into_iter
creates an iterator,Iterator::filter_map
appliesResult::ok
toWalkDir::DirEntry
and filters out the directories.
std::fs::Metadata::modified
returns theSystemTime::elapsed
time since the last modification.Duration::as_secs
converts the time to seconds and compared with 24 hours (24 * 60 * 60 seconds).Iterator::for_each
prints the file names.
use walkdir::WalkDir;use anyhow::Result;use std::env;fn main() -> Result<()> { let current_dir = env::current_dir()?; println!("Entries modified in the last 24 hours in {:?}:", current_dir); for entry in WalkDir::new(current_dir) .into_iter() .filter_map(|e| e.ok()) .filter(|e| e.metadata().unwrap().is_file()) { let path = entry.path(); let metadata = entry.metadata()?; let modified = metadata.modified()?.elapsed()?.as_secs(); if modified < 24 * 3600 { println!("{}", path.display()); } } Ok(())}
Find loops for a given path
Usesame_file::is_same_file
to detect loops for a given path.For example, a loop is created on a Unix system via symlinks:
mkdir -p /tmp/foo/bar/bazln -s /tmp/foo/ /tmp/foo/bar/baz/qux
The following would assert that a loop exists.
use walkdir::WalkDir;use same_file::is_same_file;fn main() { let mut loop_found = false; for entry in WalkDir::new(".") .follow_links(true) .into_iter() .filter_map(|e| e.ok()) { let ancestor = entry.path() .ancestors() .skip(1) .find(|ancestor| is_same_file(ancestor, entry.path()).is_ok()); if ancestor.is_some() { loop_found = true; } } // Note: This test would only pass if there are actual symlink loops // println!("Loop found: {}", loop_found);}
Recursively find duplicate file names
Find recursively in the current directory duplicate filenames,printing them only once.
use walkdir::WalkDir;use std::collections::HashMap;fn main() { let mut filenames = HashMap::new(); for entry in WalkDir::new(".") .into_iter() .filter_map(Result::ok) .filter(|e| e.file_type().is_file()) { let f_name = String::from(entry.file_name().to_string_lossy()); let counter = filenames.entry(f_name.clone()).or_insert(0); *counter += 1; if *counter == 2 { println!("{}", f_name); } }}# Recursively find all files with given predicate[![walkdir-badge]][walkdir] [![cat-filesystem-badge]][cat-filesystem]Find JSON files modified within the last day in the current directory.Using [`follow_links`] ensures symbolic links are followed like they werenormal directories and files.```rust,edition2021use walkdir::WalkDir;use anyhow::Result;fn main() -> Result<()> { for entry in WalkDir::new(".") .follow_links(true) .into_iter() .filter_map(|e| e.ok()) { let f_name = entry.file_name().to_string_lossy(); let sec = entry.metadata()?.modified()?; if f_name.ends_with(".json") && sec.elapsed()?.as_secs() < 86400 { println!("{}", entry.path().display()); } } Ok(())}
Traverse directories while skipping dotfiles
Usesfilter_entry
to descend recursively into entries passing theis_not_hidden
predicate thus skipping hidden files and directories.Iterator::filter_map
appliesis_not_hidden
on eachWalkDir::DirEntry
even if the parent is a hidden directory.
Root dir"."
yields throughWalkDir::depth
usage inis_not_hidden
predicate.
use walkdir::{DirEntry, WalkDir};fn is_not_hidden(entry: &DirEntry) -> bool { entry .file_name() .to_str() .map(|s| entry.depth() == 0 || !s.starts_with(".")) .unwrap_or(false)}fn main() { WalkDir::new(".") .into_iter() .filter_entry(|e| is_not_hidden(e)) .filter_map(|v| v.ok()) .for_each(|x| println!("{}", x.path().display()));}
Recursively calculate file sizes at given depth
Recursion depth can be flexibly set byWalkDir::max_depth
. Calculatessum of all file sizes to 3 subdir levels, ignoring files in the root directory.
use walkdir::WalkDir;fn main() { let total_size = WalkDir::new(".") .max_depth(3) .into_iter() .filter_map(|entry| entry.ok()) .filter_map(|entry| entry.metadata().ok()) .filter(|metadata| metadata.is_file()) .fold(0, |acc, m| acc + m.len()); println!("Total size: {} bytes.", total_size);}
Find all png files recursively
Recursively find all PNG files in the current directory.In this case, the**
pattern matches the current directory and all subdirectories.
Use the**
pattern in any path portion. For example,/media/**/*.png
matches all PNGs inmedia
and it's subdirectories.
use glob::glob;use anyhow::Result;fn main() -> Result<()> { for entry in glob("**/*.png")? { println!("{}", entry?.display()); } Ok(())}
Find all files with given pattern ignoring filename case
Find all image files in the/media/
directory matching theimg_[0-9]*.png
pattern.
A customMatchOptions
struct is passed toglob_with
instead ofglob
to make the glob pattern case insensitive while keeping the other optionsDefault
.
use walkdir::WalkDir;use anyhow::Result;use glob::{glob_with, MatchOptions};fn main() -> Result<()> { let options = MatchOptions { case_sensitive: false, ..Default::default() }; for entry in glob_with("/media/img_[0-9]*.png", options)? { println!("{}", entry?.display()); } Ok(())}