You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 16:33:25