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

如何用纯Win32 API查找稀疏文件空洞?求ISO C代码示例

Win32下查找稀疏文件的所有空洞

在Win32平台上,没有直接对应POSIX系统lseek(..., SEEK_HOLE, ...)/lseek(..., SEEK_DATA, ...)的API,但可以通过**DeviceIoControl函数配合FSCTL_GET_RETRIEVAL_POINTERS**控制码实现相同功能。这个控制码能获取文件的簇分配信息,通过分析返回的检索指针数组,就能区分已分配的数据段和未分配的空洞区域。

实现思路

  1. 以只读方式打开目标文件,获取文件句柄。
  2. 调用DeviceIoControl发送FSCTL_GET_RETRIEVAL_POINTERS请求,获取文件的检索指针列表。
  3. 遍历检索指针数组,对比相邻指针的位置,识别数据段和空洞:
    • 连续的分配指针覆盖的区域是数据段;
    • 指针间隙对应的未分配区域就是空洞。
  4. 处理文件末尾到实际文件大小之间的未分配区域(如果存在)。

ISO C代码示例

#include <windows.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

#define BUFFER_SIZE 4096

void PrintFileRanges(HANDLE hFile, LPCWSTR fileName) {
    LARGE_INTEGER fileSize;
    if (!GetFileSizeEx(hFile, &fileSize)) {
        wprintf(L"Failed to get file size. Error: %u\n", GetLastError());
        return;
    }

    // 获取文件所在卷的簇大小
    WCHAR drivePath[MAX_PATH];
    if (!GetVolumePathNameW(fileName, drivePath, MAX_PATH)) {
        wprintf(L"Failed to get volume path. Error: %u\n", GetLastError());
        return;
    }

    DWORD sectorsPerCluster, bytesPerSector;
    if (!GetDiskFreeSpaceW(drivePath, &sectorsPerCluster, &bytesPerSector, NULL, NULL)) {
        wprintf(L"Failed to get disk cluster info. Error: %u\n", GetLastError());
        return;
    }
    LONGLONG bytesPerCluster = (LONGLONG)sectorsPerCluster * bytesPerSector;

    wprintf(L"file %s\n", fileName);

    STARTING_VCN_INPUT_BUFFER inputBuffer = {0};
    inputBuffer.StartingVcn.QuadPart = 0;

    RETRIEVAL_POINTERS_BUFFER* outputBuffer = malloc(BUFFER_SIZE);
    if (!outputBuffer) {
        wprintf(L"Memory allocation failed.\n");
        return;
    }

    DWORD bytesReturned;
    while (TRUE) {
        if (!DeviceIoControl(hFile, FSCTL_GET_RETRIEVAL_POINTERS,
                            &inputBuffer, sizeof(inputBuffer),
                            outputBuffer, BUFFER_SIZE,
                            &bytesReturned, NULL)) {
            if (GetLastError() == ERROR_MORE_DATA) {
                free(outputBuffer);
                outputBuffer = malloc(bytesReturned);
                if (!outputBuffer) {
                    wprintf(L"Memory allocation failed.\n");
                    return;
                }
                continue;
            } else {
                wprintf(L"DeviceIoControl failed. Error: %u\n", GetLastError());
                free(outputBuffer);
                return;
            }
        }
        break;
    }

    LONGLONG currentPos = 0;
    DWORD i;
    for (i = 0; i < outputBuffer->ExtentCount; i++) {
        LONGLONG nextVcn = outputBuffer->Extents[i].NextVcn.QuadPart;
        LONGLONG lcn = outputBuffer->Extents[i].Lcn.QuadPart;
        LONGLONG extentStart = currentPos;
        LONGLONG extentEnd = nextVcn * bytesPerCluster;

        // 识别当前位置到数据段起始点之间的空洞
        if (currentPos < extentStart) {
            wprintf(L"hole from pos %lld...pos %lld\n", currentPos, extentStart - 1);
        }

        // LCN为-1表示该区域未分配,否则为数据段
        if (lcn != -1) {
            wprintf(L"data from pos %lld...pos %lld\n", extentStart, extentEnd - 1);
        }

        currentPos = extentEnd;
    }

    // 处理文件末尾到实际文件大小的剩余空洞
    if (currentPos < fileSize.QuadPart) {
        wprintf(L"hole from pos %lld...pos %lld\n", currentPos, fileSize.QuadPart - 1);
    }

    free(outputBuffer);
}

int wmain(int argc, wchar_t* argv[]) {
    if (argc != 2) {
        wprintf(L"Usage: %s <file path>\n", argv[0]);
        return 1;
    }

    HANDLE hFile = CreateFileW(argv[1], GENERIC_READ, FILE_SHARE_READ, NULL,
                               OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
    if (hFile == INVALID_HANDLE_VALUE) {
        wprintf(L"Failed to open file. Error: %u\n", GetLastError());
        return 1;
    }

    PrintFileRanges(hFile, argv[1]);
    CloseHandle(hFile);
    return 0;
}

示例输出

file xyz.data
data from pos 0...pos 16383
hole from pos 16384...pos 65535
data from pos 65546...pos 100020

内容的提问来源于stack exchange,提问作者Cedric Blancher

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 04:46:34