0


C++ CreateFileMapping 内存映射实现快速读取文件

一、简述共享内存

共享内存的方式原理就是将一份物理内存映射到不同进程各自的虚拟地址空间上,这样每个进程都可以读取同一份数据,从而实现进程通信。因为是通过内存操作实现通信,因此是一种最高效的数据交换方法。

本文主要讲述的使用内存映射文件的目的是访问磁盘上的数据文件。你可以不必对文件执行I / O操作,并且可以不必对文件内容进行缓存。

二、函数API

1、CreateFileMapping// 创建一个内存映射文件的内核对象


HANDLE CreateFileMapping(
  HANDLE hFile,                                      // 文件句柄,填写 INVALID_HANDLE_VALUE
  LPSECURITY_ATTRIBUTES lpFileMappingAttributes,    // 安全描述符,填写 NULL             
  DWORD flProtect,                                   // 映射对象保护属性
  DWORD dwMaximumSizeHigh,                           // 文件映射的最大长度的高32位
  DWORD dwMaximumSizeLow,                            // 文件映射的最大长度的低32位
  LPCTSTR lpName                                     // 文件映射对象名称
);

2、**MapViewOfFile **// 将内存映射文件映射到进程的虚拟地址中


LPVOID MapViewOfFile(
  HANDLE hFileMappingObject,  // CreateFileMapping()返回的文件映像对象句柄
  DWORD dwDesiredAccess,      // 数据的访问方式
  DWORD dwFileOffsetHigh,     // 文件映射起始偏移的高32位
  DWORD dwFileOffsetLow,      // 文件映射起始偏移的低32位
  DWORD dwNumberOfBytesToMap  // 文件中要映射的字节数,为0表示映射整个文件映射对象
);

3、OpenFileMapping // 在接收进程中打开对应的内存映射对象

// 如果函数成功,返回值是指定文件映射对象的打开句柄。失败返回 NULL。


HANDLE OpenFileMapping(
  DWORD dwDesiredAccess,  // 数据的访问方式
  BOOL bInheritHandle,    // 是否继承句柄
  LPCTSTR lpName          // 要打开的文件映射对象名称
);

三、使用步骤

  • 使用CreateFileMapping创建一个内存映射文件内核对象,告诉操作系统内存映射文件需要的物理内存大小,这个步骤决定了内存映射文件的用途――究竟是为磁盘上的文件建立内存映射还是为多个进程共享数据建立共享内存。或者使用OpenFileMapping打开映射文件内核对象。
  • 映射文件映射对象的全部或一部分到进程的地址空间,可以认为该操作是为文件中的内容分配线型地址空间,并将线型地址和文件内容对应起来,完成该操作的函数是MapViewOfFile。

四、使用内存映射文件读文件的具体过程

  1. 调用CreateFile函数打开想要映射的文件,得到文件句柄hFile。
  2. 调用CreateFileMapping函数,并传入文件句柄hFile,为该文件创建一个内存映射内核对象,得到内存映射文件的句柄hMap。
  3. 调用MapViewOfFile函数映射整个文件或一部分到进程的虚拟地址空间。该函数返回文件映射到内存后的起始地址。使用指向这个地址的指针就可以读取文件的内容了。
  4. 调用UnmapViewOfFile函数来解除文件映射。
  5. 调用CloseHandle函数关闭文件对象,必须传入内存映射文件句柄hMap
  6. 调用CloseHandle函数关闭文件对象,必须传入文件句柄hFile。

五、示例——读超大文件

约1G身份证文件的读取(含中文、英文、特殊符号)


int main(int argc, char** argv) {

    clock_t start, finish;
    strcpy(path, argv[1]);//输入的文件名
    ios::sync_with_stdio(0);
    cin.tie(0);
    //开始计时
    start = clock();
    HANDLE hFile = CreateFile(fn_convertCharArrayToLPCWSTR(path),
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL);
    if (hFile == INVALID_HANDLE_VALUE)
    {
        cout << " CreateFile fail" << endl;
        return -1;
    }

    //创建一个文件映射内核对象
    HANDLE hFileMap = CreateFileMapping(hFile,
        NULL,
        PAGE_READWRITE,
        NULL,
        NULL,
        L"Resource");
    if (hFileMap == NULL)
    {
        cout << "CreateFileMapping fail" << endl;
        return -1;
    }

    //将文件数据映射到进程的地址空间
    char* pMapData = (char*)MapViewOfFile(hFileMap,
        FILE_MAP_ALL_ACCESS,
        NULL,
        NULL,
        NULL);
    if (pMapData == NULL)
    {
        cout << " MapViewOfFile fail" << endl;
        return -1;
    }

    //读取数据
    char* pBuf = pMapData;

    finish = clock();
    //cout << "Read 1g ID file time :" << float(finish - start) << "  ms " << endl;
    printf("读取1G身份证文件的运行时间:%f毫秒\n", (float)(finish - start));
    //计时结束
}
    //撤销文件视图
    UnmapViewOfFile(pBuf);
    //关闭映射文件句柄
    CloseHandle(hFile);
    CloseHandle(hFileMap);

六、运行结果

cmd运行程序读取1G大小的身份证文件,结果为1ms

参考文献:

CreateFileMapping , OpenFileMapping, MapViewOfFile, UnmapViewOfFile 和 FlushViewOfFile_老白436196571的博客-CSDN博客_createfilemapping

标签: 大数据

本文转载自: https://blog.csdn.net/hml111666/article/details/125672728
版权归原作者 ze言 所有, 如有侵权,请联系我们删除。

“C++ CreateFileMapping 内存映射实现快速读取文件”的评论:

还没有评论