C++17 filesystem 需手动链接 stdc++fs/lc++fs,且遍历目录须显式 try/catch 处理 filesystem_error,避免 range-for 因异常中断导致遗漏。

filesystem 在 C++17 中默认不可用,得手动开开关
不是写了 #include 就能用的。GCC 11+ 和 Clang 10+ 默认不链接 stdc++fs,MSVC 倒是内置支持,但 Linux/macOS 下必加链接选项:-lstdc++fs(GCC)或 -lc++fs(Clang)。CMake 里得显式 link:target_link_libraries(my_target stdc++fs)。漏了会报类似 undefined reference to 'std::filesystem::directory_iterator::directory_iterator(std::filesystem::path const&)' 的链接错误。
遍历目录时别直接用 range-for,小心异常中断
std::filesystem::directory_iterator 和 recursive_directory_iterator 都可能在访问某个路径时抛出 std::filesystem::filesystem_error(比如权限不足、路径被删、符号链接成环)。range-for 隐式调用 operator++,一旦抛异常就跳过后续——你根本不知道哪次迭代挂了。
稳妥做法是手动 try/catch:
for (auto iter = fs::directory_iterator("/tmp"); iter != fs::directory_iterator{}; ) {
try {
if (iter->is_regular_file()) {
std::cout << iter->path() << "\n";
}
++iter;
} catch (const fs::filesystem_error& e) {
std::cerr << "skipping " << iter->path() << ": " << e.what() << "\n";
++iter; // 别忘了推进,否则死循环
}
}
path 拼接别用 +,优先用 /= 或 / 运算符
std::filesystem::path 重载了 /(返回新 path)和 /=(原地修改),语义清晰且自动处理分隔符:fs::path{"a"} / "b" / "c.txt" 在 Windows 和 Linux 下都生成正确路径。而用 + 是字符串拼接,会丢掉平台适配逻辑,还可能多出双反斜杠或缺分隔符。
立即学习“C++免费学习笔记(深入)”;
常见误用场景:
- 错:
p = p + "/sub"→ 可能在 Windows 上变成"C:\a\/sub" - 对:
p /= "sub"或p = p / "sub" - 构造绝对路径时,用
fs::absolute(p)而非手动拼"./" + p.string()
exists() 和 is_regular_file() 不是原子操作,竞态条件得自己兜底
写类似 “如果文件存在就删它” 的逻辑时,if (exists(p)) remove(p); 是典型竞态:两次系统调用之间文件可能被删或改类型。C++17 没提供原子的 “remove_if_exists”,得靠 remove() 自身的返回值判断:
bool removed = fs::remove(p); // 返回 true 表示删成功了,false 表示不存在或无法删
同理,检查是否为普通文件后读取,中间也可能被改成目录或符号链接。真正健壮的代码得接受 filesystem_error 并按需处理,而不是依赖前置检查。
路径操作看似简单,但跨平台分隔符、权限异常、符号链接解析深度、时序竞态这四点,随便漏一个就在线上吐 core。










