Обход каталогов
Имена файлов, которые были изменены за последние 24 часа
Получение текущего рабочего каталога, вызывая env::current_dir
, затем для каждой записи в fs::read_dir
извлекаем DirEntry::path
и получаем метаданные с помощью fs::Metadata
. Метод Metadata::modified
возвращает время SystemTime::elapsed
с момента последней модификации. Метод Duration::as_secs
преобразует время в секунды и сравнивается с 24 часами (24 * 60 * 60 секунд). Метод Metadata::is_file
отфильтровывает каталоги.
#[macro_use] extern crate error_chain; use std::{env, fs}; error_chain! { foreign_links { Io(std::io::Error); SystemTimeError(std::time::SystemTimeError); } } fn main() -> Result<()> { let current_dir = env::current_dir()?; println!( "Entries modified in the last 24 hours in {:?}:", current_dir ); for entry in fs::read_dir(current_dir)? { let entry = entry?; let path = entry.path(); let metadata = fs::metadata(&path)?; let last_modified = metadata.modified()?.elapsed()?.as_secs(); if last_modified < 24 * 3600 && metadata.is_file() { println!( "Last modified: {:?} seconds, is read only: {:?}, size: {:?} bytes, filename: {:?}", last_modified, metadata.permissions().readonly(), metadata.len(), path.file_name().ok_or("No filename")? ); } } Ok(()) }
Найти зацикливания у заданного пути
Используется same_file::is_same_file
для обнаружения зацикливания по заданному пути. Например, цикл может быть создан в системе Unix через символические ссылки:
mkdir -p /tmp/foo/bar/baz
ln -s /tmp/foo/ /tmp/foo/bar/baz/qux
Следующей код будет утверждать, что цикл существует.
extern crate same_file; use std::io; use std::path::{Path, PathBuf}; use same_file::is_same_file; fn contains_loop<P: AsRef<Path>>(path: P) -> io::Result<Option<(PathBuf, PathBuf)>> { let path = path.as_ref(); let mut path_buf = path.to_path_buf(); while path_buf.pop() { if is_same_file(&path_buf, path)? { return Ok(Some((path_buf, path.to_path_buf()))); } else if let Some(looped_paths) = contains_loop(&path_buf)? { return Ok(Some(looped_paths)); } } return Ok(None); } fn main() { assert_eq!( contains_loop("/tmp/foo/bar/baz/qux/bar/baz").unwrap(), Some(( PathBuf::from("/tmp/foo"), PathBuf::from("/tmp/foo/bar/baz/qux") )) ); }
Рекурсивно найти повторяющиеся имена файлов
Найти рекурсивно в текущем каталоге дубликаты имён файлов, печатая их только один раз.
extern crate walkdir; use std::collections::HashMap; use walkdir::WalkDir; fn main() { let mut filenames = HashMap::new(); for entry in WalkDir::new(".") .into_iter() .filter_map(Result::ok) .filter(|e| !e.file_type().is_dir()) { 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); } } }
Рекурсивно найти все файлы с заданным предикатом
Найти JSON файлы, изменённые за последний день в текущем каталоге. Использование метода follow_links
гарантирует, что символические ссылки будут пройдены, как если бы они были обычными каталогами и файлами.
#[macro_use] extern crate error_chain; extern crate walkdir; use walkdir::WalkDir; error_chain! { foreign_links { WalkDir(walkdir::Error); Io(std::io::Error); SystemTime(std::time::SystemTimeError); } } 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!("{}", f_name); } } Ok(()) }
Обход каталогов с пропуском файлов с точкой в начале имени
Используется filter_entry
для рекурсивного обхода записей, передавая предикат is_not_hidden
для пропуска скрытых файлов и каталогов. Метод Iterator::filter
применяется к каждому WalkDir::DirEntry
, даже если родительский объект является скрытым каталогом.
Корневой каталог "."
передаётся в использование методом WalkDir::depth
в предикате is_not_hidden
.
extern crate walkdir; 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())); }
Рекурсивно рассчитать размеры файлов на заданной глубине
Глубина рекурсии может быть гибко установлена методами WalkDir::min_depth
и WalkDir::max_depth
. Вычисление суммы всех размеров файлов до глубины под папок в 3 уровня, игнорируя файлы в корневом каталоге.
extern crate walkdir; use walkdir::WalkDir; fn main() { let total_size = WalkDir::new(".") .min_depth(1) .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); }
Найти рекурсивно все png файлы
В этом примере выполняется задача рекурсивно найти все файлы PNG в текущем каталоге. В данном случае шаблон **
соответствует текущему каталогу и всем его подкаталогам.
Шаблон **
используется для любой части пути. Например, /media/**/*.png
соответствует всем PNG в каталоге media
и его подкаталогах.
#[macro_use] extern crate error_chain; extern crate glob; use glob::glob; error_chain! { foreign_links { Glob(glob::GlobError); Pattern(glob::PatternError); } } fn main() -> Result<()> { for entry in glob("**/*.png")? { println!("{}", entry?.display()); } Ok(()) }
Найти все файлы с заданным шаблоном, игнорируя регистр в имени файла
Найдите все файлы изображений в каталоге /media/
соответствующие образцу img_[0-9]*.png
.
Пользовательская структура MatchOptions
передаётся в функцию glob_with
делая шаблон glob нечувствительным к регистру, оставляя другие параметры по умолчанию как Default
.
#[macro_use] extern crate error_chain; extern crate glob; use glob::{glob_with, MatchOptions}; error_chain! { foreign_links { Glob(glob::GlobError); Pattern(glob::PatternError); } } 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(()) }