Windows系统如何用C++获取最大可回收字节(替代diskpart的shrink querymax)
在Windows下用C++实现磁盘卷最大可收缩空间计算
diskpart的shrink querymax命令本质是查询卷末尾未被占用的连续空间(即最后一个已分配区域之后的所有空间),我们可以通过Windows原生API直接实现这一功能,无需依赖外部工具,效率会更高。
核心实现思路
- 打开目标卷的原生设备句柄
- 通过
DeviceIoControl发送FSCTL_QUERY_ALLOCATED_RANGES控制码,获取卷上所有已分配的磁盘范围 - 遍历所有已分配范围,找到最靠后的已分配区域的结束偏移量
- 获取卷的总大小,计算总大小与该结束偏移量的差值,即为最大可回收字节数
C++代码示例
#include <windows.h> #include <iostream> #include <vector> #pragma comment(lib, "kernel32.lib") int wmain(int argc, wchar_t* argv[]) { // 替换为目标卷的设备路径,比如L"\\\\.\\C:" LPCWSTR volumePath = L"\\\\.\\C:"; // 打开卷设备,需要管理员权限 HANDLE hVolume = CreateFileW( volumePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr ); if (hVolume == INVALID_HANDLE_VALUE) { std::wcerr << L"打开卷失败,错误码: " << GetLastError() << std::endl; return 1; } // 获取卷总大小 DISK_GEOMETRY_EX diskGeometry; DWORD bytesReturned; if (!DeviceIoControl( hVolume, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, nullptr, 0, &diskGeometry, sizeof(diskGeometry), &bytesReturned, nullptr )) { std::wcerr << L"获取卷几何信息失败,错误码: " << GetLastError() << std::endl; CloseHandle(hVolume); return 1; } LONGLONG totalVolumeSize = diskGeometry.DiskSize.QuadPart; // 查询已分配范围 std::vector<ALLOCATED_RANGE> allocatedRanges; STARTING_VCN_INPUT_BUFFER inputBuffer = { 0 }; // 从第一个簇开始查询 ALLOCATED_RANGE_OUTPUT_BUFFER* pOutput = nullptr; DWORD outputSize = sizeof(ALLOCATED_RANGE_OUTPUT_BUFFER) + sizeof(ALLOCATED_RANGE) * 1024; do { delete[] pOutput; pOutput = reinterpret_cast<ALLOCATED_RANGE_OUTPUT_BUFFER*>(new BYTE[outputSize]); if (!DeviceIoControl( hVolume, FSCTL_QUERY_ALLOCATED_RANGES, &inputBuffer, sizeof(inputBuffer), pOutput, outputSize, &bytesReturned, nullptr )) { if (GetLastError() == ERROR_MORE_DATA) { outputSize = bytesReturned; continue; } else { std::wcerr << L"查询已分配范围失败,错误码: " << GetLastError() << std::endl; delete[] pOutput; CloseHandle(hVolume); return 1; } } break; } while (true); // 找到最后一个已分配范围的结束偏移量 LONGLONG lastAllocatedEnd = 0; for (DWORD i = 0; i < pOutput->NumberOfRanges; ++i) { ALLOCATED_RANGE& range = pOutput->Ranges[i]; LONGLONG endOffset = range.StartingVcn.QuadPart * diskGeometry.Geometry.BytesPerSector * diskGeometry.Geometry.SectorsPerTrack * diskGeometry.Geometry.TracksPerCylinder; endOffset += range.Length.QuadPart * diskGeometry.Geometry.BytesPerSector * diskGeometry.Geometry.SectorsPerTrack * diskGeometry.Geometry.TracksPerCylinder; if (endOffset > lastAllocatedEnd) { lastAllocatedEnd = endOffset; } } // 计算最大可回收字节数 LONGLONG maxRecoverableBytes = totalVolumeSize - lastAllocatedEnd; std::wcout << L"最大可回收字节数: " << maxRecoverableBytes << std::endl; std::wcout << L"约合: " << (maxRecoverableBytes / (1024 * 1024 * 1024.0)) << L" GB" << std::endl; // 清理资源 delete[] pOutput; CloseHandle(hVolume); return 0; }
注意事项
- 程序必须以管理员权限运行,否则无法成功打开卷设备
- 该实现仅适用于NTFS文件系统(diskpart的
shrink功能同样仅支持NTFS) - 代码中的
volumePath需要替换为目标卷的设备路径,格式为\\\\.\\X:(X为盘符) - 如果卷上没有已分配空间,最大可回收字节数即为卷的总大小
内容的提问来源于stack exchange,提问作者Dinesh Chowdary
相关产品推荐
相关产品推荐

