使用mapviewoffile随机读取文件

时间:2017-02-23 08:22:49

标签: c++ winapi

我有一个非常大的文件,我想使用CreateFileMapping和MapViewOfFile根据给定的标识号从中提取10个字节的文本。所以这就是我徒劳无功的尝试,

char* Read(char*pFilename, int id)
{
    HANDLE hFile = ::CreateFile(pFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    GetSystemInfo(&sysInfo);
    DWORD dwSysGran = sysInfo.dwAllocationGranularity;
    DWORD dwFileMapStart = ((id*10/ dwSysGran)*dwSysGran);
    DWORD dwMapViewSize = (id*10 % dwSysGran) + 10;
    DWORD dwFileMapSize = id*10 + 10;
    char data[10];
    HANDLE hMap = ::CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, dwFileMapSize, NULL);
    if (hMap != NULL)
    {
        char *rawBuffer = (char*)MapViewOfFile(hMap, FILE_MAP_READ, 0, dwFileMapStart, dwMapViewSize);
        memcpy(&data[0], rawBuffer, 10);
        UnmapViewOfFile(rawBuffer);
    }
//...
    return data;
}

例如,如果用户输入名为" characterWeaponData.ucc"的文件。和an identifier = 122 然后我的程序需要从文件中的第1220个字节开始读取10个字节的文本,并将它们返回进行进一步处理。

我根据我在SO上找到的几个资源编​​写了这段代码,直到现在我对地球上的内容一无所知

_In_     DWORD  dwFileOffsetHigh,
 _In_     DWORD  dwFileOffsetLow,

这两个功能真的意味着要做。我想我的参数如上面的程序所示传入这些参数是不正确的。

2 个答案:

答案 0 :(得分:1)

  1. 这里没有理由使用文件映射。打开,搜索和阅读。文件映射的速度并不快。

  2. dwFileOffsetHighdwFileOffsetLow组合成64位偏移到“视图”开始的文件中。从不同的偏移量开始,您可以拥有单个文件映射的多个视图。偏移量必须是页面大小的倍数。因此,无论您想要什么,都无法启动

  3. dwFileMapSize(高和低是64位值)必须是映射中可用文件的最大大小。

  4. 磁盘故障和磁盘删除可能会导致(系统)异常。如果你不希望程序在这种情况下崩溃,你需要处理它。

  5. 请注意,您的偏移规范允许10字节段跨越页边界。您必须确保您的视图延伸两页

答案 1 :(得分:0)

您的计算看起来是正确的,但您忘记了rawBuffer处的视图指向偏移dwFileMapStart而不是id*10

我会尝试这样的事情:

char* Read(char*pFilename, int id)
{
    HANDLE hFile = ::CreateFile(pFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    GetSystemInfo(&sysInfo);
    DWORD dwSysGran = sysInfo.dwAllocationGranularity;
    DWORD dwSize = 10;
    DWORD dwOffset = id*dwSize;
    DWORD dwFileMapStart = ((dwOffset/dwSysGran)*dwSysGran);
    DWORD dwMapViewSize = dwOffset + dwSize - dwFileMapStart;
    char data[10];
    HANDLE hMap = ::CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
    if (hMap != NULL)
    {
        char *rawBuffer = (char*)MapViewOfFile(hMap, FILE_MAP_READ, 0, dwFileMapStart, dwMapViewSize);
        memcpy(&data[0], rawBuffer + (dwOffset - dwFileMapStart), dwSize);
        UnmapViewOfFile(rawBuffer);
    }
//...
    return data;
}

(我没有测试过这段代码,所以可能会有一些拼写错误。但它应该给你基本的想法。)

如果文件可能大于4GB,则需要进行64位计算。

请注意(根据文件大小和应用程序的位数),维护整个文件的永久映射视图可能比每次需要读取10个字节时创建新映射更有意义。至少考虑维护永久映射对象,即使您每次都要重新映射视图;你会发现它可以显着降低开销。