用std::filesystem::recursive_directory_iterator最简单可靠,C++17起为标准方案,跨平台且自动处理符号链接、权限错误;需启用-c++17、包含<filesystem>、用try/catch捕获filesystem_error,并用is_regular_file()过滤文件。

用 std::filesystem::recursive_directory_iterator 最简单可靠
C++17 起,std::filesystem 是标准方案,不用依赖第三方库或平台 API。它能跨 Windows/Linux/macOS 工作,且自动处理符号链接、权限错误等边界情况。
关键点:必须启用 C++17 或更高标准(编译时加 -std=c++17),并链接 stdc++fs(GCC 下需显式链接,Clang 和 MSVC 通常自动处理)。
- 遍历所有文件(不含目录):
if (entry.is_regular_file()) - 跳过符号链接指向的目标(只算链接本身):
std::filesystem::directory_options::skip_permission_denied可配合使用 - 遇到无读取权限的子目录时,默认会抛
std::filesystem::filesystem_error,需用try/catch包裹迭代器构造或解引用
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main() {
try {
for (const auto& entry : fs::recursive_directory_iterator("path/to/dir")) {
if (entry.is_regular_file()) {
std::cout << entry.path().string() << "
";
}
}
} catch (const fs::filesystem_error& e) {
std::cerr << "FS error: " << e.what() << "
";
}
}
Windows 下用 FindFirstFileW / FindNextFileW 的坑
纯 Win32 API 虽然快、不依赖标准库版本,但极易写错路径通配符和循环逻辑,尤其容易漏掉根目录下的第一项或陷入无限循环。
常见错误现象:FindFirstFileW(L"dir\*", ...) 会同时匹配 . 和 ..,若不手动跳过,会导致重复遍历甚至栈溢出(递归时);WIN32_FIND_DATAW 中的 cFileName 是宽字符,直接用 printf 打印会乱码。
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 务必检查
dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY再决定是否递归 - 路径拼接必须用
std::wstring+L"\\",不能用+拼窄字符串 -
FindClose必须在每次FindFirstFileW后调用,否则句柄泄漏
Linux/macOS 下 opendir + readdir 需手动递归
opendir 只读一层,要遍历全树必须自己写递归或用栈模拟。比 std::filesystem 多出大量样板代码,且容易忽略 DT_DIR 和 DT_LNK 的区分逻辑。
典型问题:readdir 返回的 d_name 不带路径,拼接时若忘了加 / 或用了 \,会在 Linux 下导致 ENOENT;stat 检查类型前没做 strcmp(d_name, ".") == 0 || strcmp(d_name, "..") == 0 判断,会无限递归进 . 目录。
- 推荐用
fts_open(FreeBSD/POSIX 扩展),它内置递归和符号链接控制,但不是所有发行版默认启用 - 若坚持用
opendir,递归函数入口处应先chdir到目标目录,避免长路径拼接,退出前再chdir("..")
性能敏感场景下要注意 std::filesystem::status 的开销
频繁调用 entry.status() 或 entry.symlink_status() 会触发多次系统调用,在海量小文件目录中明显拖慢速度。而 is_regular_file()、is_directory() 等成员函数复用迭代器内部缓存的状态,更快。
- 不要在循环里反复写
std::filesystem::status(entry.path()) - 需要判断是否为符号链接时,优先用
entry.is_symlink(),而非status().type() == fs::file_type::symlink - 如果只要文件名不要完整路径,用
entry.path().filename().string()比entry.path().string()少一次字符串拷贝
真正麻烦的是混合了硬链接、挂载点、网络文件系统(如 NFS)的环境——std::filesystem 默认不跟随符号链接,但某些 NFS 实现会让 recursive_directory_iterator 卡住或返回异常结果,这时只能降级用平台原生 API 并加超时控制。

















