Linux下获取磁盘每秒读取字节数需两次采样/proc/diskstats第6列(读扇区数),乘512换算为字节,再除以时间间隔;须匹配主设备行(如sda)、跳过空白逐域解析,避免空格分割错位。

Linux下用/proc/diskstats解析磁盘读取字节数
直接读 /proc/diskstats 是最轻量、最可靠的方式。它不依赖第三方库,也不需要 root 权限,只要程序能读文件就行。每行代表一个设备,第 3 列是累计读取的扇区数(不是字节),需乘以 512 才是字节数。
注意:不能只看某一行就认为是“当前程序”的读取量——/proc/diskstats 统计的是整个设备的全局累计值,不是进程级指标。所谓“当前程序的磁盘读取”,实际得靠两次采样做差值,并结合你关心的设备(如 sda)来算每秒增量。
- 先用
cat /proc/diskstats | grep sda确认目标设备行号和字段位置(不同内核版本列数一致,但设备名可能为nvme0n1或mmcblk0) - 第 3 列是读取扇区数(
read_sectors),不是read_ios(那是 I/O 次数) - 采样间隔建议 ≥100ms,太短会导致差值为 0 或噪声大
- 别硬编码字段索引,用空格分割后跳过开头非数字字段,找第 3 个数字字段更健壮
Windows下用GetDiskFreeSpaceEx + 性能计数器不适用
GetDiskFreeSpaceEx 只返回剩余/总空间,和读取量无关;性能计数器(PdhAddCounter)虽然能拿到 PhysicalDiskDisk Read Bytes/sec,但它是系统级平均值,且初始化开销大、线程不安全、容易因权限或服务未启动失败。
真正可行的是 WMI 查询 Win32_PerfFormattedData_PerfDisk_PhysicalDisk 类,但字段名是 DiskReadBytesPerSec —— 它已经是“每秒”值,不是累计值。如果你要的是“累计字节数”,WMI 并不直接暴露该原始计数器(\PhysicalDisk(*)\Disk Read Bytes/sec 底层是差分计算),必须自己维护起始值并定时调用 Win32_PerfRawData_PerfDisk_PhysicalDisk 的 DiskReadBytes 字段(原始累计扇区 × 512)。
立即学习“C++免费学习笔记(深入)”;
- WMI 查询需链接
comsuppw.lib,初始化 COM(CoInitializeEx) -
Win32_PerfRawData_*类返回的是原始计数器值,含时间戳,必须配对使用才能算出速率 - 设备名在 WMI 中是
"0 C: "这类格式,不是C:,需截取或匹配DeviceID
C++跨平台封装建议:只封装采样逻辑,不抽象设备名
别写“跨平台获取当前程序磁盘读取”的通用接口——这本身是个伪需求。进程级 I/O 统计在 Linux 用 /proc/[pid]/io 的 rchar 字段(含缓存读),Windows 用 GetProcessIoCounters 的 ReadTransferCount,二者语义不等价(前者是字节流,后者是实际发往存储的字节)。而设备级累计读取(即标题所指)根本就不是按进程隔离的。
所以务实做法是:按平台分别实现设备级扇区读取采样,暴露两个函数:sample_disk_read_sectors(const std::string& dev_name) 和 sectors_to_bytes(uint64_t sectors)。其余差分、速率计算、定时逻辑全由上层业务控制。
- Linux 路径固定为
/proc/diskstats,正则匹配设备名比按行号更安全(std::regex("^(\s+\d+\s+){2}\s+(\d+)\s+" + dev_name + "\s")) - Windows 不要用
QueryPerformanceCounter做采样间隔,用std::chrono::steady_clock即可 - 避免在循环里反复
fopen/fclose,可 mmap/proc/diskstats(Linux)或缓存 WMI 查询对象(Windows)提升效率
常见错误:把rchar当磁盘读取字节数
很多开发者看到 /proc/[pid]/io 里的 rchar 就以为是“从磁盘读的字节数”,其实它是进程发起的所有读操作字节数(含 pipe、socket、内存映射文件,甚至 read(2) 从 page cache 命中的部分)。真正落到物理磁盘的,是 read_bytes 字段——但它只在启用 cgroup v1/v2 的环境下才更新,且默认关闭。
也就是说:没开 cgroup 的普通进程,read_bytes 永远是 0;开了 cgroup 后,它才统计实际提交给块设备的字节数(即你想要的“磁盘读取”)。但这就引入了部署约束,远不如直接读 /proc/diskstats 稳定。
- 检查是否启用 cgroup:运行
cat /proc/cgroups,看blkio是否 enabled > 0 - 即使启用,也要确认进程被正确加入 blkio cgroup(例如写入
/sys/fs/cgroup/blkio/mygroup/tasks) -
rchar - wchar不等于磁盘读取量,中间还经过 buffer/cache 层,无法简单折算
C++里没有“当前程序的磁盘累计读取字节数”这种现成 API,本质是设备级指标,得自己采样差分;最容易被忽略的是扇区到字节的换算系数(512),以及 Linux 下 /proc/diskstats 的字段含义和 Windows 下 WMI 原始计数器与格式化计数器的区别。


















