Linux通过/proc/[pid]/io的read_bytes字段获取进程累计读字节数(含缓存),Windows用GetProcessIoCounters的ReadTransferCount;二者均需两次采样求差计算每秒速率,容器中需注意权限,路径拼接应避免std::filesystem。

Linux下读取/proc/[pid]/io获取实时磁盘读字节数
Linux内核通过/proc/[pid]/io暴露进程I/O统计,其中read_bytes字段是自进程启动以来累计读取的字节数(含缓存命中),不是系统级物理磁盘读。直接读该文件最轻量、无需特权:
- 用
getpid()获取当前PID,拼接路径如/proc/12345/io - 逐行扫描,匹配以
read_bytes:开头的行,提取后跟的十进制数值 - 注意:该值可能为0(如进程未执行过read系统调用),或远大于实际物理读(因page cache命中不触发底层IO)
- 示例片段:
std::ifstream io("/proc/" + std::to_string(getpid()) + "/io");<br>std::string line;<br>while (std::getline(io, line)) {<br> if (line.rfind("read_bytes:", 0) == 0) {<br> auto pos = line.find_first_of("0123456789");<br> if (pos != std::string::npos) {<br> long long bytes = std::stoll(line.substr(pos));<br> // bytes即累计读字节数<br> }<br> }<br>}
Windows下用GetProcessIoCounters获取累计读操作数与字节数
Windows没有直接对应/proc/[pid]/io的机制,但GetProcessIoCounters能返回ReadOperationCount和ReadTransferCount,后者才是字节数累计值:
- 需包含
<windows.h>,传入当前进程句柄GetCurrentProcess() -
ReadTransferCount字段即累计读取字节数,单位是byte,与Linux的read_bytes语义一致 - 注意:该API返回的是用户态发起的读操作总量,不区分是否命中缓存;若程序大量使用内存映射文件(
CreateFileMapping),这部分读不会计入 - 示例关键行:
IO_COUNTERS counters;<br>if (GetProcessIoCounters(GetCurrentProcess(), &counters)) {<br> ULONGLONG total_read_bytes = counters.ReadTransferCount;<br>}
计算“每秒累计”需自行做差分,别依赖单次快照
所谓“每秒累计”本质是速率,必须至少两次采样求差——没有API能直接返回瞬时速率:
- 建议用
std::chrono::steady_clock记录时间戳,间隔1秒以上再读一次read_bytes或ReadTransferCount - 差值除以时间间隔(秒),得到平均B/s;间隔越短,波动越大;间隔过长(如10秒)会掩盖突发IO
- 容易忽略的坑:
/proc/[pid]/io在容器中可能被挂载隔离,若进程运行在Docker且未启用--privileged或--cap-add=SYS_ADMIN,可能读不到或返回0 - Windows下若进程刚启动,首次采样值可能极小,建议跳过前两次采样再开始计算
跨平台封装时避开std::filesystem路径拼接陷阱
拼接/proc/[pid]/io路径时,不要用std::filesystem::path构造,它在旧编译器(如GCC 8)可能不支持,且引入不必要的依赖:
立即学习“C++免费学习笔记(深入)”;
- 直接用
std::string拼接更稳妥:"/proc/" + std::to_string(getpid()) + "/io" - Windows路径用反斜杠,但
GetProcessIoCounters不涉及路径,无需拼接 - 若需统一接口,可定义函数返回
std::optional<uint64_t>,Linux分支读proc,Windows分支调API,失败时返回std::nullopt - 别试图用
stat()检查/proc/[pid]/io是否存在——只要进程活着,该文件必然存在;检查反而增加系统调用开销


















