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

如何检测Windows下指定磁盘扇区是否已被文件系统占用?

检测指定扇区是否被文件系统占用的实现方案

核心思路

要判断扇区是否被占用,本质是确认该扇区是否属于文件系统的已分配簇或元数据区域。直接解析不同文件系统(NTFS/FAT32等)的底层结构成本极高且易出错,建议借助Windows原生API实现。


方法一:通过DeviceIoControl查询卷位图映射

这是最直接高效的方案,利用Windows提供的卷位图获取已分配簇信息,再将扇区索引转换为簇索引进行判断。

实现步骤

  1. 打开驱动器句柄:使用CreateFile以管理员权限打开目标驱动器。
  2. 获取磁盘基础参数:通过IOCTL_DISK_GET_DRIVE_GEOMETRY_EX获取保留扇区数、每扇区字节数;通过GetDiskFreeSpace获取每簇扇区数。
  3. 扇区转簇索引:计算公式:簇索引 = (目标扇区索引 - 保留扇区数) / 每簇扇区数,若结果为负,说明扇区属于引导扇区等保留区域,直接视为已占用。
  4. 获取卷位图:通过FSCTL_GET_VOLUME_BITMAP控制码获取卷的已分配簇位图,检查对应簇的位状态(1为已分配,0为未分配)。

关键代码示例

#include <windows.h>
#include <vector>
#include <iostream>

bool IsSectorOccupied(char driveLetter, DWORD sectorIndex) {
    // 构造驱动器路径格式:\\\\.\\X:
    wchar_t drivePath[10];
    swprintf_s(drivePath, L"\\\\.\\%c:", driveLetter);

    // 打开驱动器(需管理员权限)
    HANDLE hDrive = CreateFileW(drivePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 
                                NULL, OPEN_EXISTING, 0, NULL);
    if (hDrive == INVALID_HANDLE_VALUE) {
        return false;
    }

    DISK_GEOMETRY_EX diskGeom;
    DWORD bytesReturned;
    // 获取磁盘几何信息(含保留扇区数)
    if (!DeviceIoControl(hDrive, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, 
                         &diskGeom, sizeof(diskGeom), &bytesReturned, NULL)) {
        CloseHandle(hDrive);
        return false;
    }

    DWORD sectorsPerCluster;
    DWORD bytesPerSector;
    // 获取每簇扇区数
    if (!GetDiskFreeSpaceW(drivePath, &sectorsPerCluster, &bytesPerSector, NULL, NULL)) {
        CloseHandle(hDrive);
        return false;
    }

    // 计算目标扇区对应的簇索引
    DWORD clusterIndex = (sectorIndex - diskGeom.PartitionEntry.ReservedSectors) / sectorsPerCluster;
    if (clusterIndex < 0) {
        // 扇区属于文件系统保留区域(如引导扇区),视为已占用
        CloseHandle(hDrive);
        return true;
    }

    // 动态获取卷位图(初始缓冲区可能不足)
    VOLUME_BITMAP_BUFFER bitmapHeader;
    if (!DeviceIoControl(hDrive, FSCTL_GET_VOLUME_BITMAP, NULL, 0, 
                         &bitmapHeader, sizeof(bitmapHeader), &bytesReturned, NULL)) {
        std::vector<BYTE> bitmapBuffer(bitmapHeader.BufferSize);
        VOLUME_BITMAP_BUFFER* pBitmap = reinterpret_cast<VOLUME_BITMAP_BUFFER*>(bitmapBuffer.data());
        pBitmap->StartingLcn = 0;
        if (!DeviceIoControl(hDrive, FSCTL_GET_VOLUME_BITMAP, pBitmap, sizeof(VOLUME_BITMAP_BUFFER), 
                             pBitmap, bitmapBuffer.size(), &bytesReturned, NULL)) {
            CloseHandle(hDrive);
            return false;
        }
        bitmapHeader = *pBitmap;
    }

    // 检查对应簇的位状态
    DWORD bytePos = clusterIndex / 8;
    BYTE bitMask = 1 << (clusterIndex % 8);
    bool isOccupied = (bitmapHeader.Buffer[bytePos] & bitMask) != 0;

    CloseHandle(hDrive);
    return isOccupied;
}

方法二:通过FSCTL_GET_RETRIEVAL_POINTERS关联文件(精确场景)

如果需要确认扇区具体属于哪个文件,可使用该API获取文件的簇映射信息,遍历卷内所有文件并判断目标扇区是否在其已分配簇范围内。但此方法效率较低,仅适合需要精确关联文件的场景。


注意事项

  • 权限要求:所有驱动器操作必须以管理员权限运行,否则CreateFile会返回无效句柄。
  • 文件系统兼容性:上述方法对NTFS、FAT32完全兼容,exFAT需调整部分参数适配。
  • 元数据区域:引导扇区、NTFS的MFT、FAT32的FAT表等元数据区域,即使位图未标记,也视为已占用,需单独判断。

内容的提问来源于stack exchange,提问作者Jim Bab

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 04:01:09