【问题标题】:randomly reading a file with mapviewoffile使用 mapviewofile 随机读取文件
【发布时间】:2017-02-23 08:22:49
【问题描述】:

我有一个非常大的文件,我想使用 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,

在这两个函数中真正的意思是做。而且我猜我在上面的程序显示中传递给这些的参数是不正确的。

【问题讨论】:

  • 当您可以打开文件并寻找您感兴趣的偏移量时,为什么要为此使用内存映射?
  • 64 位数字分成两个 32 位值,highest 32 bits 和 lowest 32 bits。
  • 但是在这种情况下它们有什么用以及如何使用它们?
  • @molbdnilo 因为我现在只喜欢使用 winapi。
  • 您可以使用 Win32 API 从文件中读取数据。

标签: c++ winapi


【解决方案1】:
  1. 这里几乎没有理由使用文件映射。打开、寻找和阅读。文件映射的速度并不神奇。

  2. dwFileOffsetHighdwFileOffsetLow 在“视图”开始的文件中组合为 64 位偏移量。您可以拥有单个文件映射的多个视图,从不同的偏移量开始。偏移量必须是页面大小的倍数。所以你不能让它随心所欲地开始

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

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

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

【讨论】:

    【解决方案2】:

    您的计算看起来正确,但您忘记了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 个字节时创建新映射更有意义。即使每次都想重新映射视图,至少也要考虑维护一个永久映射对象;您会发现它显着减少了开销。

    【讨论】:

    • 谢谢@Harry Johnston。程序现在正确输出。 ~))
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-08
    • 1970-01-01
    • 2023-03-21
    • 2016-09-15
    • 2016-10-09
    相关资源
    最近更新 更多