c++17起最简单可靠的方式是使用std::filesystem::recursive_directory_iterator,它自动处理符号链接循环和权限错误,但需启用-std=c++17、捕获filesystem_error异常、注意windows长路径限制及高效调用status()而非is_regular_file()。

用 std::filesystem::recursive_directory_iterator 最简单可靠
C++17 起,std::filesystem 是标准方案,不用依赖 Boost 或系统 API。它自动处理符号链接循环、权限拒绝等边界情况,比手写递归更健壮。
常见错误是忽略异常——比如遇到无读取权限的子目录时,recursive_directory_iterator 默认抛 std::filesystem::filesystem_error,不捕获就会崩溃。
- 启用 C++17:编译加
-std=c++17,GCC/Clang 还需链接-lstdc++fs(MSVC 不需要) - 遍历时用
try/catch包裹单次++iter或解引用,不要把整个循环包进去——否则出错就中断全部遍历 - 想跳过符号链接指向的目标(即只遍历链接本身),构造迭代器时传
std::filesystem::directory_options::skip_permission_denied不够,得显式传std::filesystem::directory_options::follow_symlinks的反向逻辑,实际推荐用std::filesystem::directory_options::none
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
void walk(const fs::path& p) {
try {
for (auto iter = fs::recursive_directory_iterator(p); iter != fs::recursive_directory_iterator(); ++iter) {
try {
std::cout path()
<h3>需要过滤特定类型文件?别在循环里反复调用 <code>is_regular_file()</code>
</h3>
<p>每次调用 <code>is_regular_file()</code> 都可能触发一次 <code>stat()</code> 系统调用,遍历大目录时性能明显下降。迭代器返回的 <code>directory_entry</code> 对象自带缓存,应优先用 <code>iter->status().type()</code>。</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill2659" title="C++"><img
src="https://img.php.cn/upload/skill/000/000/081/178927213426672.jpg" alt="C++" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill2659" title="C++" class="overflowclass">C++</a>
<p class="overflowclass">"空空如也"</p>
</div>
<a rel="nofollow" href="/xiazai/skill2659" title="C++" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
<ul>
<li>
<code>iter->is_regular_file()</code> 内部其实也调用了 <code>status()</code>,但没复用缓存,等价于重复 stat</li>
<li>想筛目录就用 <code>iter->is_directory()</code>,同理</li>
<li>注意 <code>status()</code> 和 <code>symlink_status()</code> 区别:前者跟随符号链接,后者只看链接本身;遍历时默认用 <code>status()</code>
</li>
</ul>
<pre class="brush:php;toolbar:false;">// ✅ 高效写法
if (iter->status().type() == fs::file_type::regular) {
// 处理普通文件
}
// ❌ 低效写法(多一次系统调用)
if (iter->is_regular_file()) { ... }
Windows 上路径分隔符和长路径问题不能忽视
Windows 默认路径最大长度 260 字符,深层嵌套目录很容易超限,此时 recursive_directory_iterator 构造或递进时会抛 filesystem_error,错误码为 winerror 206(“文件名或扩展名太长”)。
- 启用长路径支持:Windows 10 1607+ 需在注册表或组策略开启
LongPathsEnabled,否则 C++ 标准库层面无解 - 路径字符串统一用
fs::path操作,别用std::string拼接——fs::path自动处理/和\转换 - 打印路径时用
iter->path().generic_string(),避免宽字符输出乱码(尤其 MinGW)
要中断遍历或跳过子树?靠 disable_recursion_pending()
标准迭代器不提供类似 Python 的 os.walk 的“跳过当前目录下所有子目录”能力,但可通过 disable_recursion_pending() 实现局部跳过——它只对下一个直接子目录生效,不是全局开关。
- 在循环体内调用
iter.disable_recursion_pending(),下次++iter就不会进入当前项的子目录 - 必须在访问当前项后、自增前调用,顺序错了无效
- 无法回退:一旦禁用,该次迭代中不能再启用
for (auto iter = fs::recursive_directory_iterator(p); iter != fs::recursive_directory_iterator(); ++iter) {
if (iter->path().filename() == "node_modules") {
iter.disable_recursion_pending(); // 下次 ++iter 就跳过 node_modules 下所有内容
}
}
实际用下来,最常被忽略的是异常粒度控制和 Windows 长路径限制——前者导致程序莫名退出,后者让遍历卡在某个深层目录再也走不动。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










