linux 用 /proc/diskstats 第6/10列×512得累计读写字节数,注意设备名精确匹配和unsigned long long解析;windows 用 pdh 的read/write bytes total计数器,需枚举实例、两次采样取值。

Linux 下用 /proc/diskstats 解析磁盘 I/O 累计字节数
直接读 /proc/diskstats 是最轻量、最可靠的方式。它不依赖第三方库,也不需要 root 权限,只要程序能读文件就行。该文件每行代表一个磁盘或分区,第 3 列是设备名(如 sda),第 6 列是累计读取扇区数,第 10 列是累计写入扇区数——注意:单位是**扇区**(通常为 512 字节),不是字节。
常见错误是直接把第 6/10 列当字节数用,结果小了 512 倍。正确做法是乘以 512;如果要统计“当前程序所在磁盘”,得先通过 /proc/self/mounts 或 stat() 查路径挂载点,再映射到对应设备名(比如 / 挂在 sda1,就得找 sda1 行,而非 sda)。
- 用
std::ifstream逐行读/proc/diskstats,按空格分割,跳过空行和注释行 - 匹配设备名时注意:
sda1和sda是不同行,别用前缀匹配(如只查sda可能误中sda1) - 扇区数是无符号 64 位整数,务必用
unsigned long long解析,否则溢出(尤其写入量大的系统)
Windows 下通过 PDH API 获取 PhysicalDiskBytes Read/sec 等计数器
Windows 没有类似 /proc 的实时文件接口,必须走性能计数器(PDH)。但要注意:PhysicalDiskBytes Read/sec 是**瞬时速率**(每秒字节数),不是累计值;而你要的是“累计读取字节数”,对应的是 PhysicalDiskRead Bytes Total 和 PhysicalDiskWrite Bytes Total。
容易踩的坑是调用 PdhAddCounterA 时硬编码实例名(如 "_Total" 或 "0 C:"),实际需先枚举可用实例(PdhEnumObjectItems),再选目标磁盘。另外,首次调用 PdhCollectQueryData 后不能立刻取值——必须等至少一次采样周期(建议 sleep 100ms 后再调第二次 PdhCollectQueryData,否则返回 PDH_INVALID_DATA)。
- 初始化用
PdhOpenQuery,添加计数器用PdhAddCounterA,传入完整路径如"\PhysicalDisk(0 C:)\Read Bytes Total" - 用
PdhGetFormattedCounterValue取PDH_FMT_LARGE类型,结果存入LARGE_INTEGER,再转为uint64_t - 不要频繁新建 query——复用同一个 query 更稳定;计数器名大小写敏感,且含括号和空格,必须严格匹配
跨平台封装建议:避免轮询阻塞主线程
无论 Linux 还是 Windows,读磁盘统计都是 I/O 或系统调用操作,虽然快,但若每毫秒都查一次,会徒增开销。更合理的做法是:启动时记录初始值,之后定期(如 100ms~1s)采样差值,再除以时间间隔得到平均速率;累计值本身只需存一个 uint64_t 变量缓存上次读到的数值。
- 用
std::chrono::steady_clock记录每次采样时间,避免系统时间跳变影响速率计算 - Linux 下可考虑用 inotify 监控
/proc/diskstats变化(但实际变化不触发事件,所以仍需定时读) - Windows 下 PDH 查询失败很常见(如权限不足、服务未启动),需检查
PdhGetLastError()并降级处理(比如 fallback 到固定 0 值或日志告警)
为什么不用 statvfs 或 getmntent?
statvfs() 返回的是文件系统剩余/总空间,不是 I/O 累计字节数;getmntent() 只能列出挂载信息,无法关联到磁盘设备的读写计数。这两个 API 完全不提供 I/O 统计能力,试图用它们实现需求只会白费力气。
真正要累计字节数,就绕不开底层驱动暴露的统计接口:Linux 是 /proc/diskstats,Windows 是 PDH 计数器。其他任何“看起来相关”的系统调用,基本都是误导方向。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











