Linux 通过 /proc/self/io 的 read_bytes 字段获取进程自启动以来从块设备读取的字节数,Windows 则通过 GetProcessIoCounters 的 ReadTransferCount 获取;二者语义不同,均不包含网络或标准输入读取。

Linux 下读取 /proc/self/io 的 read_bytes 字段
Linux 内核通过 /proc/self/io 文件暴露进程 I/O 统计,其中 read_bytes 行记录了该进程自启动以来从块设备(含磁盘)读取的字节数(注意:不是文件系统缓存命中数,而是实际发出的底层读 I/O 字节数)。这是最直接、开销最小的方式。
- 用
std::ifstream打开/proc/self/io,逐行读取直到匹配以read_bytes:开头的行 - 解析该行冒号后的内容为
unsigned long long—— 不能用int或long,否则在大 I/O 场景下会溢出 - 该值是累加值,不随进程休眠或空闲而停止增长;但仅统计该进程发起的直接读操作,不包含子进程或内核线程代劳的读
- 如果程序以非特权用户运行,仍可读取自身
/proc/self/io,无需 root 权限
Windows 下调用 GetProcessIoCounters
Windows 没有等价的 /proc 接口,必须使用 Windows API。关键函数是 GetProcessIoCounters,它返回 IO_COUNTERS 结构体,其中 ReadTransferCount 字段即为累计读取字节数。
- 需包含
<windows.h>,链接kernel32.lib - 传入当前进程句柄:
GetCurrentProcess(),而非 PID -
ReadTransferCount是ULONGLONG类型,对应 C++ 的unsigned long long - 该计数包含所有同步/异步读操作,也包括对文件、设备、管道的读——只要底层走的是 I/O 子系统,就会被计入
- 若调用失败(返回 false),检查
GetLastError(),常见原因是权限不足(但通常读自己进程是允许的)
跨平台封装时要注意的差异
Linux 的 read_bytes 和 Windows 的 ReadTransferCount 看似等价,但语义细节不同,容易误判:
- Linux 计数单位是“实际发出到块设备的字节数”,可能因预读、合并等略高于应用层
read()总和;Windows 则统计传递给 I/O 管理器的字节数,更贴近应用层请求量 - Linux 值只增不减,即使
mmap读页也会计入(若触发缺页并从磁盘加载);Windows 对MapViewOfFile的读通常不计入ReadTransferCount,除非显式调用ReadFile - 两者都不包含网络 socket 读取,也不包含标准输入重定向(如
stdin从管道来)的字节数 - 没有标准 C++ 库函数能跨平台完成此事,必须条件编译或抽象层封装
常见错误:误读 read_chars 或 ReadOperationCount
很多人混淆了“读取字节数”和“读取操作次数”或“字符数”,导致结果偏差巨大:
立即学习“C++免费学习笔记(深入)”;
- Linux 下
/proc/self/io中的read_chars是所有read()系统调用返回的字节数总和(含缓存命中),不等于物理磁盘读;read_bytes才是你要的 - Windows 下
ReadOperationCount是读操作次数,不是字节数;ReadTransferCount才是字节数 - 用
fread()或std::ifstream::read()自己统计,会漏掉mmap、sendfile、异步 I/O 等路径,且无法区分缓存与真实磁盘读 - 试图用
statfs或GetDiskFreeSpaceEx推算,完全无效——那是设备级总量,不是进程级累计值
真正难的不是读这个数字,而是理解它到底代表什么:它是内核视角下该进程触发的底层读 I/O 总量,不是应用层感知的“文件读了多少”,也不是磁盘控制器实际传输量(那还要扣除 RAID、加密、压缩等损耗)。拿来做趋势监控可以,直接对比不同进程的绝对值要格外小心。


















