目录遍历
过去 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
用于筛选出目录。
查找给定路径的循环
使用 same_file::is_same_file
检测给定路径的循环。例如,可以通过软连接(符号链接)在 Unix 系统上创建循环:
mkdir -p /tmp/foo/bar/baz
ln -s /tmp/foo/ /tmp/foo/bar/baz/qux
下面的实例将断言存在一个循环。
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")
))
);
}
递归查找重名文件
在当前目录中递归查找重复的文件名,只打印一次。
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
确保软链接(符号链接)像普通目录和文件一样被按照当前查找规则执行。
跳过隐藏文件遍历目录
递归下行到子目录的过程中,使用 filter_entry
对目录中的条目传递 is_not_hidden
断言,从而跳过隐藏的文件和目录。Iterator::filter
可应用到要检索的任何目录 WalkDir::DirEntry
,即使父目录是隐藏目录。
根目录 "."
的检索结果,通过在断言 is_not_hidden
中使用 WalkDir::depth
参数生成。
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 层子文件夹深度的所有文件的大小总和,计算中忽略根文件夹中的文件。
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 文件。
忽略文件名大小写,使用给定模式查找所有文件
在 /media/
目录中查找与正则表达模式 img_[0-9]*.png
匹配的所有图像文件。
一个自定义 MatchOptions
结构体被传递给 glob_with
函数,使全局命令模式下不区分大小写,同时保持其他选项的默认值 Default
。
译者注:
glob
是glob command
的简写。在 shell 里面,用*
等匹配模式来匹配文件,如:ls src/*.rs。
use error_chain::error_chain;
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(())
}