使用std::filesystem::recursive_directory_iterator遍历大目录时,需设skip_permission_denied选项、用symlink_status()处理符号链接、以error_code版本避免异常,并通过inode去重硬链接,忽略目录file_size(),跨文件系统不合并inode。

std::filesystem::recursive_directory_iterator 怎么用才不卡死
直接遍历大目录时,std::filesystem::recursive_directory_iterator 默认会为每个条目调用 status(),触发多次系统调用,遇到权限不足或挂载点(如 /proc、/sys)极易卡住或抛出 filesystem_error。这不是 bug,是设计使然——它默认“安全优先”。
- 加
std::filesystem::directory_options::skip_permission_denied跳过无权访问的子目录,否则迭代器会在第一个Permission denied处 throw - 避免在循环里反复调用
file_size():对符号链接默认会解引用,可能跨设备或进入无限循环;改用symlink_status().size()获取链接本身大小 - 用
std::error_code版本构造迭代器和file_size(),把错误收进变量里处理,别让异常打断整个统计
Windows 下 GetDiskFreeSpaceEx 和 std::filesystem 的结果为什么差几百 MB
根本原因不是精度问题,而是统计口径不同:std::filesystem::file_size() 对普通文件返回真实字节数,但对目录返回的是其 metadata 占用(通常 4KB–64KB),而 Windows 的 GetDiskFreeSpaceEx 返回的是卷级空闲空间,包含未分配簇、MFT 预留、回收站残留等。两者根本不该对比。
- 要算“用户可见的文件夹总大小”,必须递归累加所有
is_regular_file()条目的file_size() -
is_directory()条目不能跳过,但它的file_size()值毫无意义,直接忽略 - NTFS 压缩或稀疏文件会导致
file_size()>disk_size(),C++ 标准库不提供磁盘实际占用查询,得调用GetCompressedFileSize(Windows)或stat.st_blocks * 512(Linux)
递归统计时如何避免重复计算硬链接
硬链接指向同一 inode,std::filesystem::file_size() 每次都返回相同值,但 naive 递归会把它算多遍。标准库没内置去重机制,得自己记 std::pair<dev_t ino_t></dev_t>。
- 用
std::filesystem::status(p, ec).type()判断是否为file_type::regular,再用std::filesystem::stat(p, ec)(C++23)或struct stat系统调用取st_dev和st_ino - 不要用路径字符串去重:硬链接路径不同,但 inode 相同
- 注意跨文件系统场景:不同
st_dev必然不同 inode 空间,无需合并判断
std::filesystem::file_size 报 “No such file or directory” 却明明存在
最常见原因是路径中含符号链接,且最后一段链接目标不存在(dangling symlink)。file_size() 默认行为是解引用,失败就报这个错,而不是返回链接本身的大小。
立即学习“C++免费学习笔记(深入)”;
- 先用
symlink_status(p, ec)判断类型,若为file_type::symlink,再用symlink_status(p, ec).size()安全获取 - 别依赖
exists(p):它对 dangling symlink 返回 false,但你可能正想统计链接文件本身的大小(比如 12 字节的路径字符串) - Linux 下注意 procfs/sysfs 中的伪文件:它们
exists()为 true,但file_size()可能返回 0 或触发 read() 时才报错
真正麻烦的从来不是“怎么写循环”,而是硬链接去重、符号链接语义、权限边界和跨文件系统行为——这些细节不显眼,但一漏就导致结果偏差 20% 以上,而且很难 debug。










