引言:为什么你需要在 Rust 中列出文件?
\n\n想象一下:你正在用 Rust 编写一个备份工具、日志分析器或简单的文件管理器。这时,一个基础但关键的任务出现了——获取指定目录中的所有文件列表。看起来很简单?但在 Rust 中,由于其严格的类型系统和所有权机制,即使是这样一个简单的操作也隐藏着一些陷阱。
\n\n问题 “How can I list files of a directory in Rust?” 是 Stack Overflow 上最热门的问题之一(数千次浏览!)。这并非偶然:新手经常在 std::fs::read_dir 上遇到困难,混淆迭代器,并忘记错误处理。在本教程中,我将向你展示两种可行的方法:简单方法(仅列出单个文件夹中的文件)和高级方法(递归遍历所有子目录)。开始吧!
1. 准备工作:创建新项目
\n\n在编写代码之前,我们先创建一个新的二进制项目。打开终端并执行:
\n\ncargo new list_files_rs\ncd list_files_rs\n\n现在打开 src/main.rs——我们将在这里编写所有代码。一开始我们不需要外部依赖,只需要 Rust 标准库 std。
2. 最简单的方法:std::fs::read_dir
\n\n函数 std::fs::read_dir 返回一个目录条目的迭代器。每个条目都是一个 DirEntry,包含文件名、路径、类型和元数据。让我们编写一个基本示例:
use std::fs;\nuse std::path::Path;\n\nfn main() -> Result<(), Box<dyn std::error::Error>> {\n let path = Path::new("."); // 当前目录\n\n // 读取文件夹内容\n let entries = fs::read_dir(path)?;\n\n for entry in entries {\n let entry = entry?; // 解包 Result\n let path = entry.path();\n\n // 检查是否为文件(不是目录)\n if path.is_file() {\n println!("{}", path.display());\n }\n }\n\n Ok(())\n}\n\n这里发生了什么?
\n- \n
fs::read_dir(path)— 打开目录并返回ReadDir(迭代器)。 \n - 我们遍历每个条目。每次调用
next()返回Result<DirEntry>— 因此需要entry?。 \n entry.path()返回文件/文件夹的完整路径。 \n - 方法
path.is_file()用于过滤掉子目录。 \n
使用命令 cargo run 运行代码 — 你将看到项目根目录中的文件列表(例如 Cargo.toml、src/main.rs)。
2.1. 按扩展名过滤
\n\n通常我们只需要特定文件,例如仅 .rs 或 .txt 文件。添加过滤器:
use std::fs;\nuse std::path::Path;\n\nfn main() -> Result<(), Box<dyn std::error::Error>> {\n let path = Path::new(".");\n\n for entry in fs::read_dir(path)? {\n let entry = entry?;\n let path = entry.path();\n\n // 检查是否为文件且扩展名为 .rs\n if path.is_file() && path.extension().map_or(false, |ext| ext == "rs") {\n println!("{}", path.display());\n }\n }\n\n Ok(())\n}\n\n使用 map_or 技巧是为了安全处理文件没有扩展名的情况 — path.extension() 返回 Option<&OsStr>。
3. 递归遍历:深入所有子文件夹
\n\n简单的 read_dir 不会进入子目录。如果你需要递归收集所有文件(例如,用于查找重复文件),你需要编写自己的递归函数。这是一个优雅的解决方案:
use std::fs;\nuse std::path::Path;\n\nfn visit_dirs(dir: &Path, depth: usize) -> Result<(), Box&l