最直接方式是用std::filesystem::directory_iterator(单层)或recursive_directory_iterator(递归),需启用C++17、包含<filesystem>、处理filesystem_error异常,并注意路径存在性检查与符号链接行为。

用 std::filesystem 遍历目录最直接(C++17+)
如果你的编译器支持 C++17(如 GCC 8+、Clang 7+、MSVC 2017 Update 15.7+),std::filesystem 是首选。它跨平台、语义清晰,且不用手动处理路径分隔符或递归逻辑。
常见错误是忽略命名空间或未启用标准库文件系统支持:
-
g++编译时需加-lstdc++fs(GCC 8–10),GCC 11+ 和 Clang 通常自动链接 - MSVC 默认开启,但需确保项目设置中启用 C++17 或更高标准
- 路径字符串建议用
u8"dir_name"或R"(path\to\dir)"避免转义问题
示例:只获取当前目录下一级文件名(不含子目录)
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
for (const auto& entry : fs::directory_iterator("data")) {
if (fs::is_regular_file(entry)) {
std::cout << entry.path().filename().string() << '\n';
}
}
需要递归遍历?用 fs::recursive_directory_iterator
和 directory_iterator 行为一致,但会进入子目录。注意它默认跳过符号链接(除非显式启用),且迭代顺序不保证稳定 —— 不要依赖“先文件后目录”或字母序。
立即学习“C++免费学习笔记(深入)”;
容易踩的坑:
- 没捕获异常:
std::filesystem::filesystem_error可能在权限不足或路径被删除时抛出,尤其在多线程/多进程环境中 - 误用
entry.path():它返回完整路径;若只要文件名,必须调用.filename(),否则得到的是"./sub/dir/file.txt"而非"file.txt" - 性能敏感场景慎用递归迭代器:它内部维护栈结构,比单层遍历略重;若只需深度 1,别用它
旧编译器(C++11/14)怎么办?用 dirent.h(Linux/macOS)或 FindFirstFile(Windows)
没有 std::filesystem 时,得写平台分支代码。别试图用 system("ls") 解析输出 —— 安全性差、不可靠、无法处理含空格或换行的文件名。
关键差异点:
- Linux/macOS:
dirent.h中readdir()返回struct dirent*,d_name字段是 C 风格字符串,需注意长度限制(NAME_MAX) - Windows:
FindFirstFile的WIN32_FIND_DATA.cFileName是宽字符(wchar_t),用MultiByteToWideChar或直接以 UTF-16 处理,避免 ANSI 乱码 - 两者都不递归;如需递归,得自己写栈或队列模拟,且要注意软链接循环引用风险
为什么不用 glob() 或 scandir()?
glob()(POSIX)看起来简洁,但它只支持简单通配符(*, ?, [...]),不支持正则,且结果不包含文件类型信息 —— 你无法区分同名的文件和目录,还得额外调用 stat() 判断,反而增加开销。
scandir() 虽然能过滤并排序,但:
- 排序函数(
alphasort)行为受 locale 影响,可能不符合预期 - 回调函数里不能抛异常(C ABI 约束),错误处理笨重
- Windows 不原生支持,需第三方移植,维护成本高
真正麻烦的不是“怎么列出文件”,而是“如何安全、可移植、可维护地做这件事”。std::filesystem 把路径解析、类型判断、异常语义都收束到标准里;如果项目卡在旧标准,优先封装一层跨平台的轻量目录遍历工具,而不是每处都写条件编译。


















