用std::filesystem::recursive_directory_iterator最简单可靠,c++17起为标准方案,跨平台且自动处理符号链接、权限错误;需启用-c++17、包含、用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
<h3>Windows 下用 <code>FindFirstFileW</code> / <code>FindNextFileW</code> 的坑</h3>
<p>纯 Win32 API 虽然快、不依赖标准库版本,但极易写错路径通配符和循环逻辑,尤其容易漏掉根目录下的第一项或陷入无限循环。</p>
<p>常见错误现象:<code>FindFirstFileW(L"dir*", ...)</code> 会同时匹配 <code>.</code> 和 <code>..</code>,若不手动跳过,会导致重复遍历甚至栈溢出(递归时);<code>WIN32_FIND_DATAW</code> 中的 <code>cFileName</code> 是宽字符,直接用 <code>printf</code> 打印会乱码。</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill5502" title="C++ Code Review Master"><img
src="https://img.php.cn/upload/skill/000/000/081/179051228971575.jpg" alt="C++ Code Review Master" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill5502" title="C++ Code Review Master" class="overflowclass">C++ Code Review Master</a>
<p class="overflowclass">组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。</p>
</div>
<a rel="nofollow" href="/xiazai/skill5502" title="C++ Code Review Master" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
<ul>
<li>务必检查 <code>dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY</code> 再决定是否递归</li>
<li>路径拼接必须用 <code>std::wstring</code> + <code>L"\\"</code>,不能用 <code>+</code> 拼窄字符串</li>
<li>
<code>FindClose</code> 必须在每次 <code>FindFirstFileW</code> 后调用,否则句柄泄漏</li>
</ul>
<h3>Linux/macOS 下 <code>opendir</code> + <code>readdir</code> 需手动递归</h3>
<p><code>opendir</code> 只读一层,要遍历全树必须自己写递归或用栈模拟。比 <code>std::filesystem</code> 多出大量样板代码,且容易忽略 <code>DT_DIR</code> 和 <code>DT_LNK</code> 的区分逻辑。</p>
<p>典型问题:<code>readdir</code> 返回的 <code>d_name</code> 不带路径,拼接时若忘了加 <code>/</code> 或用了 <code>\</code>,会在 Linux 下导致 <code>ENOENT</code>;<code>stat</code> 检查类型前没做 <code>strcmp(d_name, ".") == 0 || strcmp(d_name, "..") == 0</code> 判断,会无限递归进 <code>.</code> 目录。</p>
<ul>
<li>推荐用 <code>fts_open</code>(FreeBSD/POSIX 扩展),它内置递归和符号链接控制,但不是所有发行版默认启用</li>
<li>若坚持用 <code>opendir</code>,递归函数入口处应先 <code>chdir</code> 到目标目录,避免长路径拼接,退出前再 <code>chdir("..")</code>
</li>
</ul>
<h3>性能敏感场景下要注意 <code>std::filesystem::status</code> 的开销</h3>
<p>频繁调用 <code>entry.status()</code> 或 <code>entry.symlink_status()</code> 会触发多次系统调用,在海量小文件目录中明显拖慢速度。而 <code>is_regular_file()</code>、<code>is_directory()</code> 等成员函数复用迭代器内部缓存的状态,更快。</p>
<ul>
<li>不要在循环里反复写 <code>std::filesystem::status(entry.path())</code>
</li>
<li>需要判断是否为符号链接时,优先用 <code>entry.is_symlink()</code>,而非 <code>status().type() == fs::file_type::symlink</code>
</li>
<li>如果只要文件名不要完整路径,用 <code>entry.path().filename().string()</code> 比 <code>entry.path().string()</code> 少一次字符串拷贝</li>
</ul>
<p>真正麻烦的是混合了硬链接、挂载点、网络文件系统(如 NFS)的环境——<code>std::filesystem</code> 默认不跟随符号链接,但某些 NFS 实现会让 <code>recursive_directory_iterator</code> 卡住或返回异常结果,这时只能降级用平台原生 API 并加超时控制。</p></iostream></filesystem>C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










