递归遍历目录必须从合法路径构造directory_iterator,先验证exists(p)&&is_directory(p);统计行数用std::getline更可靠;需显式判断is_regular_file()/is_directory()并复用status()避免重复系统调用。

用 std::filesystem::directory_iterator 递归遍历目录时,别直接用默认构造
默认构造的 directory_iterator 是“end iterator”,拿它和合法迭代器比较没问题,但一旦解引用或自增就未定义行为——常见崩溃或静默跳过文件。递归必须从一个有效的路径开始。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 始终用
std::filesystem::path构造合法的directory_iterator,例如directory_iterator{p},其中p是已确认存在的目录路径 - 检查路径是否存在且为目录:用
exists(p) && is_directory(p),否则抛异常或跳过 - 递归调用前先验证子项是否可访问,避免权限错误中断整个统计(比如某些系统目录)
统计单个文件行数,std::getline 比 std::count 更可靠
std::count 数 '\n' 看似简洁,但会漏掉无换行结尾的文件最后一行;而 std::getline 每成功读一行就计数一次,语义准确。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 用
std::ifstream打开文件,配合std::string和std::getline循环计数 - 打开失败时跳过(如权限不足、符号链接断裂),不要 throw——否则整个递归中断
- 注意文本编码:C++ 标准库不自动处理 BOM 或 UTF-8 多字节换行,纯 ASCII/UTF-8 无 BOM 场景下安全
递归逻辑里,is_regular_file() 和 is_directory() 必须显式判断
文件系统里除了普通文件和目录,还有 socket、pipe、device 文件等。不加判断直接递归会触发 not_a_directory 错误或无限循环(如 /proc/self/fd 中的符号链接)。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 对每个
directory_entry先调用status()或symlink_status(),再用is_regular_file()/is_directory()判断 - 遇到符号链接,用
is_symlink()检查,按需决定是否跳过(默认跳过,避免循环引用) - Windows 下注意
junction和reparse point,is_directory()可能返回 true,但实际不是真实目录——可用!is_symlink()过滤
性能关键:避免重复 status() 调用,复用 directory_entry::status()
每次调用 is_regular_file(e) 或 is_directory(e) 都可能触发一次系统调用查状态。在循环里反复调用,I/O 开销明显上升,尤其在大目录中。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 对每个
directory_entry e,先存一份auto s = e.status(); - 后续用
is_regular_file(s)和is_directory(s),避免重复 stat - 如果还需判断是否是符号链接,统一用
s.type() == file_type::symlink,比is_symlink(e)更省一次系统调用
最易被忽略的是跨平台路径分隔符和符号链接处理:Linux/macOS 下 ../ 和软链接容易形成环,Windows 下需要额外过滤 ReparsePoint 类型。递归前做一次路径规范化(lexically_normal())并缓存已访问路径的 hash,比事后检测更稳妥。



















