CreateFileMaping

CreateFileMapping(一)

测试创建和打开文件映射的时候老是得到"句柄无效"的错误, 仔细看了MSDN以后才发觉是函数认识不透, 这里把相关的解释翻译出来

HANDLE CreateFileMapping(
  HANDLE hFile,                       //物理文件句柄
  LPSECURITY_ATTRIBUTES lpAttributes, //安全设置
  DWORD flProtect,                    //保护设置
  DWORD dwMaximumSizeHigh,            //高位文件大小
  DWORD dwMaximumSizeLow,             //低位文件大小
  LPCTSTR lpName                      //共享内存名称
);

1) 物理文件句柄
   任何可以获得的物理文件句柄, 如果你需要创建一个物理文件无关的内存映射也无妨, 将它设置成为 0xFFFFFFFF(INVALID_HANDLE_VALUE)就可以了.

   如果需要和物理文件关联, 要确保你的物理文件创建的时候的访问模式和"保护设置"匹配, 比如: 物理文件只读, 内存映射需要读写就会发生错误. 推荐你的物理文件使用独占方式创建.

   如果使用 INVALID_HANDLE_VALUE, 也需要设置需要申请的内存空间的大小, 无论物理文件句柄参数是否有效, 这样 CreateFileMapping 就可以创建一个和物理文件大小无关的内存空间给你, 甚至超过实际文件大小, 如果你的物理文件有效, 而大小参数为0, 则返回给你的是一个和物理文件大小一样的内存空间地址范围.  返回给你的文件映射地址空间是可以通过复制, 集成或者命名得到, 初始内容为0.

2) 保护设置
   就是安全设置, 不过一般设置NULL就可以了, 使用默认的安全配置. 在win2k下如果需要进行限制, 这是针对那些将内存文件映射共享给整个网络上面的应用进程使用是, 可以考虑进行限制.

3) 高位文件大小
   弟兄们, 我想目前我们的机器都是32位的东东, 不可能得到超过32位进程所能寻址的私有32位地址空间, 一般还是设置0吧, 我没有也不想尝试将它设置超过0的情况.
4) 低位文件大小
   这个还是可以进行设置的, 不过为了让其他共享用户知道你申请的文件映射的相关信息, 我使用的时候是在获得的地址空间头部添加一个结构化描述信息, 记录内存映射的大小, 名称等, 这样实际申请的空间就比输入的增加了一个头信息结构大小了, 我认为这样类似BSTR的方式应该是比较合理的.

5) 共享内存名称
   这个就是我今天测试的时候碰壁的祸根, 因为为了对于内存进行互斥访问, 我设置了一个互斥句柄, 而名称我选择和命名共享内存同名, 之下就是因为他们使用共同的namespace导致了错误, 呵呵.

7) 调用CreateFileMapping的时候GetLastError的对应错误
   ERROR_FILE_INVALID     如果企图创建一个零长度的文件映射, 应有此报
   ERROR_INVALID_HANDLE   如果发现你的命名内存空间和现有的内存映射, 互斥量, 信号量, 临界区同名就麻烦了
   ERROR_ALREADY_EXISTS   表示内存空间命名已经存在

8) 相关服务或者平台的命名保留
   Terminal Services: 
   命名可以包含 "Global" 或者 "Local" 前缀在全局或者会话名空间初级文件映射. 其他部分可以包含任何除了()以外的字符, 可以参考 Kernel Object Name Spaces.

 摘要: 本文给出了一种方便实用的解决大文件的读取、存储等处理的方法,并结合相关程序代码对具体的实现过程进行了介绍。

  引言

  文件操作是应用程序最为基本的功能之一,Win32 API和MFC均提供有支持文件处理的函数和类,常用的有Win32 API的CreateFile()、WriteFile()、ReadFile()和MFC提供的CFile类等。一般来说,以上这些函数可以满足大多数场合的要求,但是对于某些特殊应用领域所需要的动辄几十GB、几百GB、乃至几TB的海量存储,再以通常的文件处理方法进行处理显然是行不通的。目前,对于上述这种大文件的操作一般是以内存映射文件的方式来加以处理的,本文下面将针对这种Windows核心编程技术展开讨论。

  内存映射文件

  内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区域,同时将物理存储器提交给此区域,只是内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而非系统的页文件,而且在对该文件进行操作之前必须首先对文件进行映射,就如同将整个文件从磁盘加载到内存。由此可以看出,使用内存映射文件处理存储于磁盘上的文件时,将不必再对文件执行I/O操作,这意味着在对文件进行处理时将不必再为文件申请并分配缓存,所有的文件缓存操作均由系统直接管理,由于取消了将文件数据加载到内存、数据从内存到文件的回写以及释放内存块等步骤,使得内存映射文件在处理大数据量的文件时能起到相当重要的作用。另外,实际工程中的系统往往需要在多个进程之间共享数据,如果数据量小,处理方法是灵活多变的,如果共享数据容量巨大,那么就需要借助于内存映射文件来进行。实际上,内存映射文件正是解决本地多个进程间数据共享的最有效方法。

  内存映射文件并不是简单的文件I/O操作,实际用到了Windows的核心编程技术--内存管理。所以,如果想对内存映射文件有更深刻的认识,必须对Windows操作系统的内存管理机制有清楚的认识,内存管理的相关知识非常复杂,超出了本文的讨论范畴,在此就不再赘述,感兴趣的读者可以参阅其他相关书籍。下面给出使用内存映射文件的一般方法:

  首先要通过CreateFile()函数来创建或打开一个文件内核对象,这个对象标识了磁盘上将要用作内存映射文件的文件。在用CreateFile()将文件映像在物理存储器的位置通告给操作系统后,只指定了映像文件的路径,映像的长度还没有指定。为了指定文件映射对象需要多大的物理存储空间还需要通过CreateFileMapping()函数来创建一个文件映射内核对象以告诉系统文件的尺寸以及访问文件的方式。在创建了文件映射对象后,还必须为文件数据保留一个地址空间区域,并把文件数据作为映射到该区域的物理存储器进行提交。由MapViewOfFile()函数负责通过系统的管理而将文件映射对象的全部或部分映射到进程地址空间。此时,对内存映射文件的使用和处理同通常加载到内存中的文件数据的处理方式基本一样,在完成了对内存映射文件的使用时,还要通过一系列的操作完成对其的清除和使用过资源的释放。这部分相对比较简单,可以通过UnmapViewOfFile()完成从进程的地址空间撤消文件数据的映像、通过CloseHandle()关闭前面创建的文件映射对象和文件对象。

  内存映射文件相关函数

  在使用内存映射文件时,所使用的API函数主要就是前面提到过的那几个函数,下面分别对其进行介绍:

HANDLE CreateFile(LPCTSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes, 
HANDLE hTemplateFile); 

  函数CreateFile()即使是在普通的文件操作时也经常用来创建、打开文件,在处理内存映射文件时,该函数来创建/打开一个文件内核对象,并将其句柄返回,在调用该函数时需要根据是否需要数据读写和文件的共享方式来设置参数dwDesiredAccess和dwShareMode,错误的参数设置将会导致相应操作时的失败。

HANDLE CreateFileMapping(HANDLE hFile,
LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
DWORD flProtect,
DWORD dwMaximumSizeHigh,
DWORD dwMaximumSizeLow,
LPCTSTR lpName); 

  CreateFileMapping()函数创建一个文件映射内核对象,通过参数hFile指定待映射到进程地址空间的文件句柄(该句柄由CreateFile()函数的返回值获取)。要把文件映像到内存,首先必须调用CreateFileMapping()函数,它需要用一个由CreateFile()函数打开并返回的文件句柄,对大多数共享内存应用程序,必须把此句柄设置为0xFFFFFFFF,用来指定系统页面文件。通过使用上面的特殊句柄,可以不调用CreateFile函数,当然在完成时,也不必有一个内存的磁盘文件拷贝。。由于内存映射文件的物理存储器实际是存储于磁盘上的一个文件,而不是从系统的页文件中分配的内存,所以系统不会主动为其保留地址空间区域,也不会自动将文件的存储空间映射到该区域,为了让系统能够确定对页面采取何种保护属性,需要通过参数flProtect来设定,保护属性PAGE_READONLY、PAGE_READWRITE和PAGE_WRITECOPY分别表示文件映射对象被映射后,可以读取、读写文件数据。在使用PAGE_READONLY时,必须确保CreateFile()采用的是GENERIC_READ参数;PAGE_READWRITE则要求CreateFile()采用的是GENERIC_READ|GENERIC_WRITE参数;至于属性PAGE_WRITECOPY则只需要确保CreateFile()采用了GENERIC_READ和GENERIC_WRITE其中之一即可。DWORD型的参数dwMaximumSizeHigh和dwMaximumSizeLow也是相当重要的,指定了文件的最大字节数,由于这两个参数共64位,因此所支持的最大文件长度为16EB,几乎可以满足任何大数据量文件处理场合的要求。

LPVOID MapViewOfFile(HANDLE hFileMappingObject,
DWORD dwDesiredAccess,
DWORD dwFileOffsetHigh,
DWORD dwFileOffsetLow,
DWORD dwNumberOfBytesToMap);

  MapViewOfFile()函数负责把文件数据映射到进程的地址空间,参数hFileMappingObject为CreateFileMapping()返回的文件映像对象句柄。参数dwDesiredAccess则再次指定了对文件数据的访问方式,而且同样要与CreateFileMapping()函数所设置的保护属性相匹配。虽然这里一再对保护属性进行重复设置看似多余,但却可以使应用程序能更多的对数据的保护属性实行有效控制。MapViewOfFile()函数允许全部或部分映射文件,在映射时,需要指定数据文件的偏移地址以及待映射的长度。其中,文件的偏移地址由DWORD型的参数dwFileOffsetHigh和dwFileOffsetLow组成的64位值来指定,而且必须是操作系统的分配粒度的整数倍,对于Windows操作系统,分配粒度固定为64KB。当然,也可以通过如下代码来动态获取当前操作系统的分配粒度:

SYSTEM_INFO sinf;
GetSystemInfo(&sinf);
DWORD dwAllocationGranularity = sinf.dwAllocationGranularity;

  参数dwNumberOfBytesToMap指定了数据文件的映射长度,这里需要特别指出的是,对于Windows 9x操作系统,如果MapViewOfFile()无法找到足够大的区域来存放整个文件映射对象,将返回空值(NULL);但是在Windows 2000下,MapViewOfFile()只需要为必要的视图找到足够大的一个区域即可,而无须考虑整个文件映射对象的大小。

  在完成对映射到进程地址空间区域的文件处理后,需要通过函数UnmapViewOfFile()完成对文件数据映像的释放,该函数原型声明如下:

BOOL UnmapViewOfFile(LPCVOID lpBaseAddress);

  唯一的参数lpBaseAddress指定了返回区域的基地址,必须将其设定为MapViewOfFile()的返回值。在使用了函数MapViewOfFile()之后,必须要有对应的UnmapViewOfFile()调用,否则在进程终止之前,保留的区域将无法释放。除此之外,前面还曾由CreateFile()和CreateFileMapping()函数创建过文件内核对象和文件映射内核对象,在进程终止之前有必要通过CloseHandle()将其释放,否则将会出现资源泄漏的问题。

  除了前面这些必须的API函数之外,在使用内存映射文件时还要根据情况来选用其他一些辅助函数。例如,在使用内存映射文件时,为了提高速度,系统将文件的数据页面进行高速缓存,而且在处理文件映射视图时不立即更新文件的磁盘映像。为解决这个问题可以考虑使用FlushViewOfFile()函数,该函数强制系统将修改过的数据部分或全部重新写入磁盘映像,从而可以确保所有的数据更新能及时保存到磁盘。

使用内存映射文件处理大文件应用示例

  下面结合一个具体的实例来进一步讲述内存映射文件的使用方法。该实例从端口接收数据,并实时将其存放于磁盘,由于数据量大(几十GB),在此选用内存映射文件进行处理。下面给出的是位于工作线程MainProc中的部分主要代码,该线程自程序运行时启动,当端口有数据到达时将会发出事件hEvent[0],WaitForMultipleObjects()函数等待到该事件发生后将接收到的数据保存到磁盘,如果终止接收将发出事件hEvent[1],事件处理过程将负责完成资源的释放和文件的关闭等工作。下面给出此线程处理函数的具体实现过程:

 

 

例子1……
// 创建文件内核对象,其句柄保存于hFile
HANDLE hFile = CreateFile("Recv1.zip",
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_READ, 
NULL,
CREATE_ALWAYS, 
FILE_FLAG_SEQUENTIAL_SCAN, 
NULL);

// 创建文件映射内核对象,句柄保存于hFileMapping
HANDLE hFileMapping = CreateFileMapping(hFile,NULL,PAGE_READWRITE, 
0, 0x4000000, NULL);
// 释放文件内核对象
CloseHandle(hFile);

// 设定大小、偏移量等参数
__int64 qwFileSize = 0x4000000;
__int64 qwFileOffset = 0;
__int64 T = 600 * sinf.dwAllocationGranularity;
DWORD dwBytesInBlock = 1000 * sinf.dwAllocationGranularity;

// 将文件数据映射到进程的地址空间
PBYTE pbFile = (PBYTE)MapViewOfFile(hFileMapping,
FILE_MAP_ALL_ACCESS,
(DWORD)(qwFileOffset>>32), (DWORD)(qwFileOffset&0xFFFFFFFF), dwBytesInBlock);
while(bLoop) 
{
// 捕获事件hEvent[0]和事件hEvent[1]
DWORD ret = WaitForMultipleObjects(2, hEvent, FALSE, INFINITE); 
ret -= WAIT_OBJECT_0;
switch (ret)
{
// 接收数据事件触发
case 0:
// 从端口接收数据并保存到内存映射文件
nReadLen=syio_Read(port[1], pbFile + qwFileOffset, QueueLen);
qwFileOffset += nReadLen;

// 当数据写满60%时,为防数据溢出,需要在其后开辟一新的映射视图
if (qwFileOffset > T)
{
T = qwFileOffset + 600 * sinf.dwAllocationGranularity;
UnmapViewOfFile(pbFile);
pbFile = (PBYTE)MapViewOfFile(hFileMapping,
FILE_MAP_ALL_ACCESS,
(DWORD)(qwFileOffset>>32), (DWORD)(qwFileOffset&0xFFFFFFFF), dwBytesInBlock);
}
break;

// 终止事件触发
case 1:
bLoop = FALSE;

// 从进程的地址空间撤消文件数据映像
UnmapViewOfFile(pbFile);

// 关闭文件映射对象
CloseHandle(hFileMapping);
break;
}
}

 

  在终止事件触发处理过程中如果只简单的执行UnmapViewOfFile()和CloseHandle()函数将无法正确标识文件的实际大小,即如果开辟的内存映射文件为30GB,而接收的数据只有14GB,那么上述程序执行完后,保存的文件长度仍是30GB。也就是说,在处理完成后还要再次通过内存映射文件的形式将文件恢复到实际大小,下面是实现此要求的主要代码:

 

// 创建另外一个文件内核对象
hFile2 = CreateFile("Recv.zip", 
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_READ, 
NULL,
CREATE_ALWAYS, 
FILE_FLAG_SEQUENTIAL_SCAN,
NULL);

// 以实际数据长度创建另外一个文件映射内核对象
hFileMapping2 = CreateFileMapping(hFile2,
NULL, 
PAGE_READWRITE,
0,
(DWORD)(qwFileOffset&0xFFFFFFFF),
NULL);

// 关闭文件内核对象
CloseHandle(hFile2);

// 将文件数据映射到进程的地址空间
pbFile2 = (PBYTE)MapViewOfFile(hFileMapping2, 
FILE_MAP_ALL_ACCESS, 
0, 0, qwFileOffset);

// 将数据从原来的内存映射文件复制到此内存映射文件
memcpy(pbFile2, pbFile, qwFileOffset);

file://从进程的地址空间撤消文件数据映像
UnmapViewOfFile(pbFile);
UnmapViewOfFile(pbFile2);

// 关闭文件映射对象
CloseHandle(hFileMapping);
CloseHandle(hFileMapping2);

// 删除临时文件
DeleteFile("Recv1.zip");


例子2:

共享内存的使用

  在Windows操作系统下,任何一个进程不允许读取、写入或是修改另一个进程的数据(包括变量、对象和内存分配等),但是在某个进程内创建的文件映射对象的视图却能够为多个其他进程所映射,这些进程共享的是物理存储器的同一个页面。因此,当一个进程将数据写入此共享文件映射对象的视图时,其他进程可以立即获取数据变更情况。为了进一步提高数据交换的速度,还可以采用由系统页文件支持的内存映射文件而直接在内存区域使用,显然这种共享内存的方式是完全可以满足在进程间进行大数据量数据快速传输任务要求的。下面给出在两个相互独立的进程间通过文件映射对象来分配和访问同一个共享内存块的应用实例。在本例中,由发送方程序负责向接收方程序发送数据,文件映射对象由发送方创建和关闭,并且指定一个唯一的名字供接收程序使用。接收方程序直接通过这个唯一指定的名字打开此文件映射对象,并完成对数据的接收。

  在发送方程序中,首先通过CreateFileMapping()函数创建一个内存映射文件对象,如果创建成功则通过MapViewOfFile()函数将此文件映射对象的视图映射进地址空间,同时得到此映射视图的首址。可见,共享内存的创建主要是通过这两个函数完成的。这两个函数原形声明如下:

HANDLE CreateFileMapping(HANDLE hFile,
LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
DWORD flProtect,
DWORD dwMaximumSizeHigh,
DWORD dwMaximumSizeLow,
LPCTSTR lpName);
LPVOID MapViewOfFile(HANDLE hFileMappingObject,
DWORD dwDesiredAccess,
DWORD dwFileOffsetHigh,
DWORD dwFileOffsetLow,
DWORD dwNumberOfBytesToMap);


  CreateFileMapping()函数参数hFile指定了待映射到进程地址空间的文件句柄,如果为无效句柄则系统会创建一个使用来自页文件而非指定磁盘文件存储器的文件映射对象。很显然,在本例中为了数据能快速交换,需要人为将此参数设定为INVALID_HANDLE_VALUE;参数flProtect设定了系统对页面采取的保护属性,由于需要进行读写操作,因此可以设置保护属性PAGE_READWRITE;双字型参数dwMaximumSizeHigh和dwMaximumSizeLow指定了所开辟共享内存区的最大字节数;最后的参数lpName用来给此共享内存设定一个名字,接收程序可以通过这个名字将其打开。MapViewOfFile()函数的参数hFileMappingObject为CreateFileMapping()返回的内存文件映像对象句柄;参数dwDesiredAccess再次指定对其数据的访问方式,而且需要同CreateFileMapping()函数所设置的保护属性相匹配。这里对保护属性的重复设置可以确保应用程序能更多的对数据的保护属性进行有效控制。下面给出创建共享内存的部分关键代

hRecvMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 1000000, "DataMap");
if (hRecvMap != NULL)
{
lpData = (LPBYTE)MapViewOfFile(hRecvMap, FILE_MAP_WRITE, 0, 0, 0);
if (lpData == NULL)
{
CloseHandle(hRecvMap);
hRecvMap = NULL;
}
}
// 通知接收程序内存文件映射对象的视图已经打开
HWND hRecv = ::FindWindow(NULL, DECODE_PROGRAMM);
if (hRecv != NULL)
::PostMessage(hRecv, WM_MAP_OPEN, 0, 0);


  数据的传送实际是将数据从发送方写到共享内存中,然后由接收程序及时从中取走即可。数据从发送方程序写到共享内存比较简单,只需用memcpy()函数将数据拷贝过去,关键在于能及时通知接收程序数据已写入到共享内存,并让其即使取走。在这里仍采取消息通知的方式,当数据写入共享内存后通过PostMessage()函数向接收方程序发送消息,接收方在消息响应函数中完成对数据的读取:

// 数据复制到共享内存
memcpy(lpData, RecvBuf, sizeof(RecvBuf));
// 通知接收方接收数据
HWND hDeCode = ::FindWindow(NULL, DECODE_PROGRAMM);
if (hDeCode != NULL)
::PostMessage(hDeCode, WM_DATA_READY, (WPARAM)0, (LPARAM)sizeof(RecvBuf));


  当数据传输结束,即将退出程序时,需要将映射进来的内存文件映射对象视图卸载和资源的释放等处理。这部分工作主要由UnmapViewOfFile()和CloseHandle()等函数完成:

HWND hDeCode = ::FindWindow(NULL, DECODE_PROGRAMM);
if (hDeCode != NULL)
::PostMessage(hDeCode, WM_MAP_CLOSE, 0, 0);
if (lpData != NULL)
{
UnmapViewOfFile(lpData);
lpData = NULL;
}
if (hRecvMap != NULL)
{
CloseHandle(hRecvMap);
hRecvMap = NULL;
}


  在接收程序中,在收到由发送放发出的WM_MAP_OPEN消息后,由OpenFileMapping()函数打开由名字"DataMap"指定的文件映射对象,如果执行成功,继续用MapViewOfFile()函数将此文件映射对象的视图映射到接收应用程序的地址空间并得到其首址:

m_hReceiveMap = OpenFileMapping(FILE_MAP_READ, FALSE, "DataMap");
if (m_hReceiveMap == NULL)
return;
m_lpbReceiveBuf = (LPBYTE)MapViewOfFile(m_hReceiveMap,FILE_MAP_READ,0,0,0);
if (m_lpbReceiveBuf == NULL)
{
CloseHandle(m_hReceiveMap);
m_hReceiveMap=NULL;
}


  当发送方程序将数据写入到共享内存后,接收方将收到消息WM_DATA_READY,在响应函数中将数据从共享内存复制到本地缓存中,再进行后续的处理。同发送程序类似,在接收程序数据接收完毕后,也需要用UnmapViewOfFile()、CloseHandle()等函数完成对文件视图等打开过资源的释放:

// 从共享内存接收数据
memcpy(RecvBuf, (char*)(m_lpbReceiveBuf), (int)lParam);
……
// 程序退出前资源的释放
UnmapViewOfFile(m_lpbReceiveBuf);
m_lpbReceiveBuf = NULL;
CloseHandle(m_hReceiveMap);
m_hReceiveMap = NULL;


  小结

  经实际测试,使用共享内存在处理大数据量数据的快速交换时表现出了良好的性能,在数据可靠性等方面要远远高于发送WM_COPYDATA消息的方式。这种大容量、高速的数据共享处理方式在设计高速数传通讯类软件中有着很好的使用效果。本文所述代码在Windows 2000下由Microsoft Visual C++ 6.0编译通过。

摘自:http://www.yesky.com/42/1720542_1.shtml
  结论

  经实际测试,内存映射文件在处理大数据量文件时表现出了良好的性能,比通常使用CFile类和ReadFile()和WriteFile()等函数的文件处理方式具有明显的优势。本文所述代码在Windows 98下由Microsoft Visual C++ 6.0编译通过。

 

例子:

void CreateFileMappingEx() 

DWORD timebegin = ::timeGetTime(); 
HANDLE fp = CreateFile(TEXT("E:\\jyzhj2.rar"),//这里输入需要复制的文件 src 
GENERIC_READ | GENERIC_WRITE, 
FILE_SHARE_READ, 
NULL, 
OPEN_EXISTING, 
FILE_FLAG_SEQUENTIAL_SCAN, 
NULL); 
if(fp == NULL) 

cout<<"错误"<<endl; 
return; 

DWORD dwBytesInBlock = GetFileSize(fp,NULL); //文件长度 
// 创建文件映射内核对象,句柄保存于hFileMapping 
HANDLE hFileMapping = CreateFileMapping(fp, 
NULL, 
PAGE_READWRITE, 
0,//(DWORD)(dwBytesInBlock >> 16), 
dwBytesInBlock,//(DWORD)(dwBytesInBlock & 0x0000FFFF), 
NULL); 
int dwError = GetLastError(); 
// 释放文件内核对象 
CloseHandle(fp); 
// 偏移地址 
__int64 qwFileOffset = 0; 
// 将文件数据映射到进程的地址空间 
LPVOID pbFile = (LPVOID)MapViewOfFile( hFileMapping, 
FILE_MAP_ALL_ACCESS, 
(DWORD)(qwFileOffset >> 32), 
(DWORD)(qwFileOffset & 0xFFFFFFFF), 
dwBytesInBlock); 
HANDLE wp = CreateFile( TEXT("E://仙剑5.rar"),//这里输入 需要粘贴的文件 dst 
GENERIC_READ | GENERIC_WRITE, 
FILE_SHARE_WRITE, 
NULL, 
CREATE_ALWAYS, 
FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_WRITE_THROUGH, 
NULL); 
HANDLE hFileMapping2 = CreateFileMapping( wp, 
NULL, 
PAGE_READWRITE, 
0,//(DWORD)(dwBytesInBlock >> 16), 
dwBytesInBlock,//(DWORD)(dwBytesInBlock & 0x0000FFFF), 
NULL); 
CloseHandle(wp); 
LPVOID pbFile2 = (LPVOID)MapViewOfFile( hFileMapping2, 
FILE_MAP_ALL_ACCESS, 
(DWORD)(qwFileOffset >> 32), 
(DWORD)(qwFileOffset & 0xFFFFFFFF), 
dwBytesInBlock); 
memcpy(pbFile2,pbFile,dwBytesInBlock); 
UnmapViewOfFile(pbFile2); 
UnmapViewOfFile(pbFile); 
CloseHandle(hFileMapping2); 
CloseHandle(hFileMapping); 
DWORD timeend = ::timeGetTime(); 
cout<<"CreateFileMapping和MapViewOfFile程序运行时间为"<<timeend - timebegin<<endl; 
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值