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 << iter->path() << "n";
} catch (const fs::filesystem_error& e) {
// 某个文件属性读取失败(如被占用),跳过
continue;
}
}
} catch (const fs::filesystem_error& e) {
// 根目录无法打开(如权限不足),整体失败
std::cerr << "Cannot enter " << p << ": " << e.what() << "n";
}
}
需要过滤特定类型文件?别在循环里反复调用 is_regular_file()
每次调用 is_regular_file() 都可能触发一次 stat() 系统调用,遍历大目录时性能明显下降。迭代器返回的 directory_entry 对象自带缓存,应优先用 iter->status().type()。
-
iter->is_regular_file()内部其实也调用了status(),但没复用缓存,等价于重复 stat - 想筛目录就用
iter->is_directory(),同理 - 注意
status()和symlink_status()区别:前者跟随符号链接,后者只看链接本身;遍历时默认用status()
// ✅ 高效写法
if (iter->status().type() == fs::file_type::regular) {
// 处理普通文件
}
// ❌ 低效写法(多一次系统调用)
if (iter->is_regular_file()) { ... }
Windows 上路径分隔符和长路径问题不能忽视
Windows 默认路径最大长度 260 字符,深层嵌套目录很容易超限,此时 recursive_directory_iterator 构造或递进时会抛 filesystem_error,错误码为 winerror 206(“文件名或扩展名太长”)。
立即学习“C++免费学习笔记(深入)”;
- 启用长路径支持: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 长路径限制——前者导致程序莫名退出,后者让遍历卡在某个深层目录再也走不动。
文章来自机圈观察员网,发布者:,转载请注明出处:https://www.jqgcy.com/xinjizixun/126779.html