目录穿梭
过去 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 run() -> 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(()) } # # quick_main!(run);
查找给定路径的循环
使用same_file::is_same_file
检测给定路径的循环。例如,可以通过符号链接,在 UNIX 系统上,创建一个循环:
mkdir -p /tmp/foo/bar/baz
ln -s /tmp/foo/ /tmp/foo/bar/baz/qux
/tmp/foo/bar/baz/qux == /tmp/foo/ => /tmp/foo/bar/baz => /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 run() -> 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(()) } # # quick_main!(run);
跳过点(隐藏)文件时,遍历目录
使用filter_entry
深度递归,传递的是is_not_hidden
断言,因此跳过隐藏的文件和目录。Iterator::filter
应用到每个WalkDir::DirEntry
,即使父目录是隐藏目录。
根目录"."
的结果输出,是通过is_not_hidden
断言中WalkDir::depth
的使用。
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
,会匹配media
下的所有 PNG,且是子目录。
# #[macro_use] # extern crate error_chain; extern crate glob; use glob::glob; # # error_chain! { # foreign_links { # Glob(glob::GlobError); # Pattern(glob::PatternError); # } # } fn run() -> Result<()> { for entry in glob("**/*.png")? { println!("{}", entry?.display()); } Ok(()) } # # quick_main!(run);
查找具有给定模式的所有文件,忽略文件名大小写。
在/media/
目录中查找所有图像文件,要匹配img_[0-9]*.png
模式。
一个自定义的MatchOptions
结构,传递给glob_with
函数,可以使全局模式不区分大小写,同时保留其他选项的默认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 run() -> Result<()> { let options = MatchOptions { case_sensitive: false, ..Default::default() }; for entry in glob_with("/media/img_[0-9]*.png", &options)? { println!("{}", entry?.display()); } Ok(()) } # # quick_main!(run);