c++17起最简单可靠的目录遍历方案是std::filesystem::directory_iterator,跨平台、自动处理路径与编码,需启用c++17标准并注意异常处理和隐藏文件过滤。

用 std::filesystem::directory_iterator 遍历最简单可靠
C++17 起,std::filesystem 是标准方案,无需第三方库,跨平台(Windows/macOS/Linux 均支持),且自动处理路径分隔符、编码等细节。只要编译器支持 C++17(如 GCC 8+、Clang 7+、MSVC 2017 Update 5+),就优先用它。
常见错误是漏加编译选项:-std=c++17(GCC/Clang)或开启 `/std:c++17`(MSVC);链接时部分旧版 GCC 还需显式加 -lstdc++fs。
基础用法示例:
#include <filesystem>
#include <iostream>
<p>namespace fs = std::filesystem;</p><p><span>立即学习</span>“<a href="https://pan.quark.cn/s/6e7abc4abb9f" style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">C++免费学习笔记(深入)</a>”;</p><p>int main() {
for (const auto& entry : fs::directory_iterator("path/to/dir")) {
if (entry.is_regular_file()) {
std::cout << entry.path().filename() << "
";
}
}
}-
entry.path()返回完整路径,.filename()提取文件名(含扩展名) - 用
entry.is_regular_file()过滤掉子目录、符号链接等,避免误判 - 若需递归遍历所有子目录,改用
fs::recursive_directory_iterator
Windows 下用 FindFirstFileW + FindNextFileW 的注意事项
纯 Win32 API 方案仍被部分遗留项目使用,但必须用宽字符函数(W 版本),否则中文路径会乱码或失败——这是最常踩的坑。
关键点:
- 传入路径必须是
L"..."形式,且结尾加L"\*"(如L"C:\test\*"),否则无法匹配文件 -
WIN32_FIND_DATAW中的cFileName是WCHAR[260],需用wprintf或转为 UTF-8 再输出 - 首次调用
FindFirstFileW后,必须配对调用FindClose,否则句柄泄漏 - 该 API 不区分文件/目录,需检查
dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
Linux/macOS 下用 opendir/readdir 时绕过 . 和 ..
readdir 返回的 dirent 结构体中,d_name 字段会包含当前目录(".")和父目录("..")条目,不手动跳过会导致逻辑错误或无限递归。
典型处理方式:
struct dirent* ent;
DIR* dir = opendir("path/to/dir");
while ((ent = readdir(dir)) != nullptr) {
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
continue;
}
// 此处处理真实文件/子目录名
}-
opendir返回nullptr表示路径不存在或无权限,务必检查 -
readdir不保证顺序,如需排序得先收集到容器再std::sort - 文件类型判断需额外调用
stat(),不能仅靠d_type(某些文件系统不填此字段)
跨平台封装时别忽略 std::filesystem::status 的异常行为
直接对 directory_iterator 中的 entry.path() 调用 fs::is_regular_file() 看似方便,但若目标路径被其他进程删除或权限突变,可能抛出 std::filesystem::filesystem_error。生产环境不捕获会 crash。
稳妥做法是显式检查状态:
try {
auto s = fs::status(entry.path());
if (fs::is_regular_file(s)) { /* ... */ }
} catch (const fs::filesystem_error&) {
// 忽略无效项,或记录日志
}- 不建议全局
try/catch包裹整个循环——单个路径异常不该中断全部遍历 -
fs::status比fs::is_regular_file多一次系统调用,但换来健壮性,值得 - 若需高性能批量判断(如扫描百万级小文件),可考虑用
fs::directory_options::skip_permission_denied配合迭代器构造参数
实际写的时候,最容易被忽略的是:不同系统对“隐藏文件”的定义不一致(Linux 看 . 开头,Windows 看属性位),std::filesystem 默认不跳过它们——如果业务逻辑需要过滤,得自己加判断。











