应使用std::filesystem::recursive_directory_iterator遍历所有regular_file并累加file_size(),跳过目录和符号链接,捕获权限异常,用uintmax_t防溢出,并在Unix平台用st_dev/st_ino去重硬链接。

用 std::filesystem::recursive_directory_iterator 遍历并累加文件大小
这是 C++17 起最直接、标准且跨平台的方式。它自动处理符号链接(默认不跟随)、子目录递归、权限拒绝等边界情况,比手写 opendir/readdir 安全得多。
关键点:必须启用 C++17 或更高标准(如 -std=c++17),并在编译时链接 stdc++fs(GCC 早期版本需显式链接,Clang/macOS 通常不需要)。
- 对每个
std::filesystem::directory_entry,先用e.is_regular_file()过滤,再调用std::filesystem::file_size(e)获取大小;跳过目录、socket、设备文件等非普通文件 - 遇到权限不足或路径不存在的条目会抛出
std::filesystem::filesystem_error,建议用try/catch捕获并跳过(不中断整个遍历) -
file_size()返回uintmax_t,注意用足够宽的整型累加(如uint64_t),避免 32 位溢出
Windows 下用 FindFirstFileExW + 手动递归更省内存但难移植
当目标仅限 Windows 且文件树极深(数万级嵌套)、内存受限时,Win32 API 的手动递归可避免 std::filesystem 内部维护的栈空间开销。但它不跨平台,且容易漏掉符号链接或硬链接计数逻辑。
常见错误:直接用 FindFirstFile(L"*.*", ...) 会漏掉无扩展名文件;正确做法是用 L"*" 并过滤 FILE_ATTRIBUTE_DIRECTORY 标志。
立即学习“C++免费学习笔记(深入)”;
- 递归前检查
dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY,且排除.和..目录项 - 对每个文件调用
GetFileSizeEx()(返回LARGE_INTEGER),而非已废弃的GetFileSize() - 必须显式关闭每个
hFind句柄,否则快速遍历大量子目录时可能耗尽句柄资源
避免重复统计硬链接和符号链接
Linux/macOS 上,同一文件可能通过多个硬链接被多次计入总大小,导致结果虚高。C++17 的 std::filesystem 默认不解析符号链接(即只统计链接文件本身大小,不统计目标),但硬链接仍会被分别计算。
若需去重,得记录 std::filesystem::status(e).st_dev 和 std::filesystem::status(e).st_ino(即设备号+inode号),用 std::set<:pair ino_t>></:pair> 缓存已见过的 inode,仅对新 inode 累加大小。
- 注意:Windows NTFS 也支持硬链接(
mklink /H),其st_dev/st_ino语义与 POSIX 一致,该方法同样适用 - 符号链接是否跟随由构造
recursive_directory_iterator时传入的std::filesystem::directory_options::follow_directory_symlink控制;默认不跟随,所以不会误入循环引用目录
性能敏感场景下慎用 std::filesystem::file_size
每次调用 file_size() 都触发一次系统调用(stat() 或等价),在 SSD 上单次约 1–5 μs,但百万小文件下仍可能成为瓶颈。若只需粗略估算,可跳过 is_regular_file() 检查,直接对所有 entry 尝试 file_size() 并捕获异常——但会多出大量异常开销,实际更慢。
- 真正提速的办法是批量获取元数据:Linux 可用
getdents64()+statx()(需内核 4.11+),但 C++ 标准库不提供封装,得写平台特定代码 - 对于普通项目,优先确保逻辑正确;只有实测发现
file_size()占 CPU >30% 时,才值得引入复杂优化 - 别忘了磁盘 I/O 本身才是最大延迟来源——顺序读取 100 万个文件的 inode,比随机访问快 5–10 倍,而
recursive_directory_iterator的遍历顺序基本是目录项物理顺序,已相对友好
硬链接去重和跨平台异常处理是最容易被跳过的两处,尤其在测试环境只有普通文件时完全看不出问题,一到生产环境就统计翻倍或崩溃。


















