在 C++17 标准中加入了 <filesystem> 头文件,它为文件系统操作提供了一套现代、跨平台的接口。下面将演示如何使用 std::filesystem::recursive_directory_iterator 来递归遍历一个目录,并打印出所有文件路径。示例代码兼顾了错误处理、文件属性检查以及路径格式化等细节。
#include <iostream>
#include <filesystem>
#include <string>
namespace fs = std::filesystem;
int main()
{
// 1. 获取要遍历的根目录
fs::path root_dir = fs::current_path(); // 也可以改为 fs::path("/some/path");
// 2. 检查路径是否存在且为目录
if (!fs::exists(root_dir)) {
std::cerr << "路径不存在: " << root_dir << '\n';
return 1;
}
if (!fs::is_directory(root_dir)) {
std::cerr << "给定路径不是目录: " << root_dir << '\n';
return 1;
}
// 3. 创建递归目录迭代器
// 迭代器会自动忽略符号链接循环,除非你显式开启
for (auto const &entry : fs::recursive_directory_iterator(root_dir)) {
try {
const fs::path &p = entry.path();
// 打印相对路径,方便查看
std::cout << std::setw(4) << entry.depth() << ' ' << p.filename() << '\n';
// 根据需求可做进一步筛选,例如只打印 .cpp 文件
if (p.extension() == ".cpp") {
std::cout << " -> C++ 源文件\n";
}
// 如果需要读取文件大小
if (fs::is_regular_file(entry.status())) {
std::uintmax_t sz = fs::file_size(p);
std::cout << " 大小: " << sz << " 字节\n";
}
} catch (const fs::filesystem_error &e) {
std::cerr << "访问错误: " << e.what() << '\n';
// 继续遍历
}
}
return 0;
}
关键点说明
-
命名空间别名
namespace fs = std::filesystem;让代码更简洁。 -
递归迭代器
fs::recursive_directory_iterator会自动进入子目录。若想禁用符号链接递归,可使用fs::directory_options::follow_directory_symlink控制。 -
错误处理
std::filesystem的大部分操作会抛出fs::filesystem_error。在遍历时使用 try‑catch 可以保证单个错误不会终止整个程序。 -
深度信息
entry.depth()返回从根目录开始的层级深度,便于输出树状结构。 -
文件属性
fs::is_regular_file(entry.status())用来区分普通文件与目录。fs::file_size(p)给出文件大小。 -
跨平台兼容
该代码在 Windows、Linux 和 macOS 上均能正常编译运行,前提是编译器支持 C++17(如 GCC 8+、Clang 7+、MSVC 19.14+)。
扩展思路
- 过滤器:可以用
fs::directory_options::skip_permission_denied或自定义谓词来过滤特定文件类型或大小范围。 - 异步遍历:结合
std::async或线程池,对大型项目进行并行文件统计。 - 路径规范化:使用
fs::weakly_canonical(p)或fs::canonical(p)解决相对路径与符号链接的混乱。
通过上述示例,你已经掌握了在 C++17 中使用 `
` 进行递归目录遍历的基本方法。可以在此基础上进一步开发更复杂的文件系统工具,例如文件备份、日志收集或资源管理器等。