应使用 std::filesystem::recursive_directory_iterator 遍历子目录和文件,它自动深度优先遍历并支持跳过权限错误;需处理 filesystem_error 异常或设置 skip_permission_denied 选项。

怎么用 std::filesystem 遍历子目录和文件
直接用 std::filesystem::recursive_directory_iterator,它会自动进入子目录,按深度优先顺序返回所有 directory_entry。别手写递归——容易漏掉符号链接、权限错误或循环引用。
常见错误是没捕获异常:access_denied 或 not_a_directory 会抛 std::filesystem::filesystem_error,不处理就 crash。默认构造的迭代器不跳过异常,得手动加 try/catch 或用 std::filesystem::directory_options::skip_permission_denied。
- 用法示例:
for (auto& entry : std::filesystem::recursive_directory_iterator(path, std::filesystem::directory_options::skip_permission_denied)) { if (entry.is_regular_file()) { std::cout << entry.path() << "\n"; } } - 想只遍历当前层?换用
std::filesystem::directory_iterator,它不进子目录 - 路径末尾带斜杠不影响,但传入空字符串或非法路径会立即抛异常
std::filesystem::is_directory 和 is_regular_file 判断不准?
不是函数不准,是调用前没确认 entry 状态是否已缓存。directory_entry 默认惰性加载元数据,首次调用 is_* 才去查系统。如果中间路径被删/权限变,可能抛异常;更糟的是,某些平台(如 Windows)对符号链接默认不解析,is_directory() 返回 false 即使它指向一个目录。
- 保险做法:先调
entry.status()或entry.symlink_status(),再判断类型 - 区分真实类型和链接目标:用
status()查链接目标,symlink_status()查链接本身 - Windows 下注意:NTFS 重解析点(如 junction)会被
is_directory()误判,必须用symlink_status().type() == std::filesystem::file_type::directory
跨平台遍历时路径分隔符和编码问题
std::filesystem::path 内部统一用 / 存储,无论 Windows 还是 Linux,path.native() 才转成本地格式(Windows 上变成 \)。但真正要注意的是字符编码:Windows API 默认用当前代码页(如 GBK),而 C++17 标准要求 std::filesystem 接收 UTF-8 字符串(GCC/Clang)或宽字符(MSVC)。
立即学习“C++免费学习笔记(深入)”;
- Linux/macOS:传 UTF-8
std::string安全 - MSVC:推荐用
std::wstring构造path,否则含中文路径可能失败 - 避免拼接路径用
+:用/操作符,例如p / "sub" / "file.txt",它自动处理分隔符 - 打印路径别直接
cout :用p.string()(UTF-8)或p.wstring()(宽字符)显式转换
性能差?大量小文件遍历时卡顿
慢通常不是 recursive_directory_iterator 本身的问题,而是每步都触发系统调用查元数据。比如只想要文件名,却反复调 entry.is_regular_file(),等于每个 entry 都 stat 一次。
- 优化方法:用
entry.file_size()前先确认类型,或批量用std::filesystem::status(entry)一次取回全部信息 - 不需要递归?改用
directory_iterator+ 手动栈管理,避免深度优先的隐式调用开销 - Windows 上尤其明显:启用“8.3 短文件名”或杀软实时扫描会拖慢 10 倍以上,测试时关掉这些干扰项
- 别在循环里反复构造
path对象,复用变量减少临时对象分配
最常被忽略的一点:std::filesystem 在 GCC 需要链接 -lstdc++fs,Clang 要 -lc++fs,MSVC 默认开启但需确保项目设置为 C++17 或更高。忘了加链接选项,编译通过但运行时报 undefined symbol。










