如何通过WinAPI获取指定进程的磁盘I/O及网络数据?PDH是否可行?
获取Windows进程磁盘/网络数据的WinAPI实现方案
一、PDH(Performance Data Helper)完全可以实现需求
资源监视器的大部分磁盘、网络性能数据本身就来自Windows性能计数器,而PDH是微软提供的专门操作性能计数器的API,完全能满足你的需求。
关键计数器路径
针对指定进程(可通过进程名或PID定位),常用计数器路径如下:
- 磁盘读写:
- 读字节速率:
\Process ID(<PID>)\IO Read Bytes/sec - 写字节速率:
\Process ID(<PID>)\IO Write Bytes/sec - 累计读字节:
\Process ID(<PID>)\IO Read Bytes - 累计写字节:
\Process ID(<PID>)\IO Write Bytes
- 读字节速率:
- 网络收发:
- 接收字节速率:
\Process ID(<PID>)\Bytes Received/sec - 发送字节速率:
\Process ID(<PID>)\Bytes Sent/sec - 累计接收字节:
\Process ID(<PID>)\Bytes Received - 累计发送字节:
\Process ID(<PID>)\Bytes Sent
- 接收字节速率:
注:如果用进程名定位,若存在多个同名进程,需用
\Process(<进程名>#<序号>)\...格式(比如\Process(notepad#1)\...),但用PID更准确,避免序号变化的问题。
PDH实现步骤(C++示例)
- 初始化查询句柄:
PDH_HQUERY query; PDH_STATUS status = PdhOpenQuery(NULL, 0, &query); if (status != ERROR_SUCCESS) { // 处理错误 }
- 添加目标计数器:
PDH_HCOUNTER diskReadCounter; wchar_t counterPath[256]; swprintf_s(counterPath, L"\\Process ID(%d)\\IO Read Bytes/sec", targetPID); status = PdhAddCounter(query, counterPath, 0, &diskReadCounter); if (status != ERROR_SUCCESS) { // 处理错误 }
- 采集并获取数据:
// 第一次采集(初始值) PdhCollectQueryData(query); Sleep(1000); // 间隔1秒 // 第二次采集 PdhCollectQueryData(query); PDH_FMT_COUNTERVALUE value; status = PdhGetFormattedCounterValue(diskReadCounter, PDH_FMT_DOUBLE, NULL, &value); if (status == ERROR_SUCCESS) { double readRate = value.doubleValue; // 输出或处理速率值 }
- 清理资源:
PdhRemoveCounter(diskReadCounter); PdhCloseQuery(query);
PDH的优缺点
- 优点:API封装度高,实现简单,直接对应资源监视器的显示数据,无需解析底层事件。
- 缺点:速率值依赖两次采集的时间差,实时性略差;部分计数器可能因系统版本或权限问题无法访问(需管理员权限读取系统进程数据)。
二、其他WinAPI实现方案
如果需要更细粒度或实时性更高的数据,可使用以下方法:
1. ETW(Event Tracing for Windows)
通过订阅系统级IO和网络事件,直接捕获进程的磁盘操作、网络包数据。例如:
- 磁盘IO:订阅
Microsoft-Windows-FileIO提供者的事件,解析FileIoRead、FileIoWrite事件中的进程ID和字节数。 - 网络:订阅
Microsoft-Windows-TCPIP或Microsoft-Windows-Winsock-AFD提供者的事件,提取进程的TCP/UDP收发数据。
ETW实现复杂度较高,但能获取最原始的操作细节,适合需要深度分析的场景。
2. 原生系统信息查询API
- 磁盘IO:调用
NtQuerySystemInformation并传入SystemProcessIoInformation参数,可获取每个进程的累计磁盘读写字节数(需自行计算速率)。 - 网络:使用
GetExtendedTcpTable和GetExtendedUdpTable获取TCP/UDP连接列表,关联进程ID后统计收发字节数;但该方法仅针对已建立的连接,无法覆盖所有网络操作。
内容的提问来源于stack exchange,提问作者CurtisB
相关产品推荐
相关产品推荐

