




已阅读5页,还剩6页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
windows sdk编程系列文章 - 内存映射文件2008-04-13 19:40本课中我们将要讲解内存映射文件并且演示如何运用它。您将会发现使用内存映射文件是非常简单的。理论:如果您仔细地研究了前一课的例子, 就会发现它有一个严重的缺陷:如果您想读的内容大于系统分配的内存块怎么办?如果您想搜索的字符串刚好超过内存块的边界又该如何处理?对于第一个问题,您也许会说,只要不断地读就不解决了吗。至于第二个问题,您又会说在内存块的边界处做一些特别的处理,譬如放上一些标志位就可以了。原理上确实是行得通,但是这随问题复杂程度加深而显得非常难以处理。其中的第二个问题是有名的边界判断问题,程序中许许多多的错误都是由此引起。想一想,如果我们能够分配一个能够容纳整个文件的大内存块该多好啊,这样这两个问题不都迎刃而解了吗?是的,WIN32的内存映射文件确实允许我们分配一个装得下现实中可能存在的足够大的文件的内存。利用内存映射文件您可以认为操作系统已经为您把文件全部装入了内存,然后您只要移动文件指针进行读写即可了。这样您甚至不需要调用那些分配、释放内存块和文件输入/输出的API函数,另外您可以把这用作不同的进程之间共享数据的一种办法。运用内存映射文件实际上没有涉及实际的文件操作,它更象为每个进程保留一个看得见的内存空间。至于把内存映射文件当成进程间共享数据的办法来用,则要加倍小心,因为您不得不处理数据的同步问题,否则您的应用程序也许很可能得到过时或错误的数据甚至崩溃。本课中我们将主要讲述内存映射文件,将不涉及进程间的同步。WIN32中的内存映射文件应用非常广泛,譬如:即使是系统的核心模块-PE格式文件装载器也用到了内存映射文件,因为PE格式的文件并不是一次性加载到内存中来的,譬如他它在首次加载时只加载必需加载的部分,而其他部分在用到时再加载,这正好可以利用到内存映射文件的长处。实际中的大多数文件存取都和PE加载器类似,所以您在处理该类问题时也应该充分利用内存映射文件。内存映射文件本身还是有一些局限性的,譬如一旦您生成了一个内存映射文件,那么您在那个会话期间是不能够改变它的大小的。所以内存映射文件对于只读文件和不会影响其大小的文件操作是非常有用的。当然这并不意味着对于会引起改变其大小的文件操作就一定不能用内存影射文件的方法,您可以事先估计操作后的文件的可能大小,然后生成这么大小一块的内存映射文件,然后文件的长度就可以增长到这么一个大小。 我们的解释够多的了,接下来我们就看看实现的细节:1. 调用CreateFile打开您想要映射的文件。 2. 调用CreateFileMapping,其中要求传入先前CreateFile返回的句柄,该函数生成一个建立在CreateFile函数创建的文件对象基础上的内存映射对象。 3. 调用MapViewOfFile函数映射整个文件的一个区域或者整个文件到内存。该函数返回指向映射到内存的第一个字节的指针。 4. 用该指针来读写文件。 5. 调用UnmapViewOfFile来解除文件映射。 6. 调用CloseHandle来关闭内存映射文件。注意必须传入内存映射文件的句柄。 7. 调用CloseHandle来关闭文件。注意必须传入由CreateFile创建的文件的句柄。 例子:见光盘FirstWindow11下面的例子允许用户通过“打开文件”对话框来打开一个文件,然后用内存映射文件来打开该文件,如果成功,窗口的标题条会显示打开的文件的名称,您可以通过选择“File/Save”菜单项来把换名保存。该程序将会把打开的文件的内容存到新文件中去。注意,这整个过程您根本就没有用到GlobalAlloc这样的分配内存的函数。 #include Windows.h#include tchar.hTCHAR ClassName = _T(Win32FileMappingClass);TCHAR AppName = _T(Win32 File Mapping Example);TCHAR MenuName = _T(FirstMenu);HINSTANCE g_hInstance;#define IDM_OPEN 1#define IDM_SAVE 2#define IDM_EXIT 3#define MAXSIZE 260OPENFILENAME g_ofn;TCHAR FilterString = _T(All Files0*.*0Text Files0*.txt0);TCHAR bufferMAXSIZE;HANDLE hMapFile;HANDLE hFileRead;HANDLE hFileWrite;HMENU hMenu;void *pMemory;DWORD SizeWritten;void CloseMapFile() CloseHandle(hMapFile); hMapFile = NULL; CloseHandle(hFileRead);INT_PTR CALLBACK ProcWinMain( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam ) switch(Msg) case WM_CREATE: hMenu = GetMenu(hWnd); g_ofn.lStructSize = sizeof(g_ofn); g_ofn.hwndOwner = hWnd; g_ofn.hInstance = g_hInstance; g_ofn.lpstrFilter = FilterString; g_ofn.lpstrFile = buffer; g_ofn.nMaxFile = MAXSIZE; break; case WM_DESTROY: if(hMapFile !=0) CloseMapFile(); PostQuitMessage(0); break; case WM_COMMAND: if(lParam = 0) if(LOWORD(wParam) = IDM_OPEN) g_ofn.Flags = OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST |OFN_LONGNAMES|OFN_EXPLORER|OFN_HIDEREADONLY; if(GetOpenFileName(&g_ofn) hFileRead = CreateFile(buffer,GENERIC_READ,0,NULL,OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE,NULL); hMapFile = CreateFileMapping(hFileRead,NULL,PAGE_READONLY,0,0,NULL); SetWindowText(hWnd,buffer + g_ofn.nFileOffset); EnableMenuItem(hMenu,IDM_OPEN,MF_GRAYED); EnableMenuItem(hMenu,IDM_SAVE,MF_ENABLED); else if(LOWORD(wParam) = IDM_SAVE) g_ofn.Flags = OFN_LONGNAMES|OFN_EXPLORER|OFN_HIDEREADONLY; if(GetSaveFileName(&g_ofn) hFileWrite = CreateFile(buffer,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL, CREATE_NEW,FILE_ATTRIBUTE_ARCHIVE,NULL); pMemory = MapViewOfFile(hMapFile,FILE_MAP_READ,0,0,0); int nSize = GetFileSize(hFileRead,NULL); WriteFile(hFileWrite,pMemory,nSize,&SizeWritten,NULL); UnmapViewOfFile(pMemory); CloseMapFile(); CloseHandle(hFileWrite); SetWindowText(hWnd,AppName); EnableMenuItem(hMenu,IDM_OPEN,MF_ENABLED); EnableMenuItem(hMenu,IDM_SAVE,MF_GRAYED); else DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd,Msg,wParam,lParam); return 0;int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) WNDCLASSEX wc; MSG msg; HWND hWnd; g_hInstance = hInstance; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = ProcWinMain; wc.cbClsExtra = NULL; wc.cbWndExtra = NULL; wc.hInstance = hInstance; wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszMenuName = MenuName; wc.lpszClassName = ClassName; wc.hIcon = wc.hIconSm = LoadIcon(NULL,IDI_APPLICATION); wc.hCursor = LoadCursor(NULL,IDC_ARROW); RegisterClassEx(&wc); hWnd = CreateWindowEx(WS_EX_CLIENTEDGE,ClassName,AppName,WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,CW_USEDEFAULT,300,200,NULL,NULL,hInstance,NULL); ShowWindow(hWnd,SW_SHOWNORMAL); UpdateWindow(hWnd); while(GetMessage(&msg,NULL,0,0) TranslateMessage(&msg); DispatchMessage(&msg); return msg.wParam;分析: hFileRead = CreateFile(buffer,GENERIC_READ,0,NULL,OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE,NULL); 当用户选择打开文件时,我们调用CreateFile来打开。注意我们指定GENERIC_READ(一般的读)来表示我们打开的文件只能够读出,把dwShareMode设成0,表示我们不想其他进程在我们操作文件时来存取该文件。 hMapFile = CreateFileMapping(hFileRead,NULL,PAGE_READONLY,0,0,NULL);我们调用CreateFileMapping来在打开的文件的基础上生成内存映射文件。CreateFileMapping的语法如下:HANDLE CreateFileMapping( HANDLE hFile, LPSECURITY_ATTRIBUTES lpAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCTSTR lpName );您应当知道该函数并没有必要把整个文件映射到内存中去,您可以用该函数来只映射文件的一部分。您可以在参数dwMaximumSizeHigh和dwMaximumSizeLow中指定内存映射文件的大小,如果您指定的值大于实际的文件,则实际的文件将增长到指定的大小,如果想要映射的内存大小正好和文件的实际大小相等,则把两个参数中都设成为0。您可以设定lpFileMappingAttributes为NULL,让WINDOWS赋予该内存映射文件于缺省的安全属性。flProtect定义了内存映射文件的保护属性,我们指定它为PAGE_READONLY来规定该内存映射文件只能够读。注意该属性不能和CreateFile中指定的属性相矛盾,否则就不能生成内存映射文件。lpName指定内存映射文件的名称,如果您想要该内存映射文件同时可以供其它的进程使用,就必须给它取个名称。不过在我们的例子中,只有我们的进程使用该内存映射文件故我们忽略该参数。 SetWindowText(hWnd,buffer + g_ofn.nFileOffset);如果函数CreateFileMapping调用成功,我们把窗口的标题条换成被打开文件的名称。保存在缓冲区中的文件名是带有路径的全文件名,所以为了只显示文件名我们需要利用OPENFILENAME结构体中的成员nFileOffset的值来找到文件名的起始地址。 EnableMenuItem(hMenu,IDM_OPEN,MF_GRAYED); EnableMenuItem(hMenu,IDM_SAVE,MF_ENABLED);为了避免用户一次性打开多个文件,我们让“打开文件”菜单项呈灰色显示,使得打开文件的菜单项失效。函数EnableMenuItem可以用来改变菜单项的属性。 之后用户可能保存文件或者直接关闭应用程序。如果用户选择关闭应用程序,则事先必须关闭内存映射文件和打开的文件, 代码如下: case WM_DESTROY: if(hMapFile !=0) CloseMapFile(); PostQuitMessage(0); break;在上面的代码段中,当WINDOWS的消息处理过程接收到WM_DESTROY消息后,它首先检测hMapFile值是否为0。如果不为0则表示相关的文件未关闭,这样就需要调用CloseMapFile来关闭它们。void CloseMapFile() CloseHandle(hMapFile); hMapFile = NULL; CloseHandle(hFileRead);上述过程调用是用来关闭内存映射文件和原来打开的文件的,这样可以使得程序退出时没有资源泄漏。如果用户选择保存文件的话,就弹出一个“保存文件”对话框,当用户输入了新文件的名称后,我们调用CreateFile函数来创建新文件-输出文件。 pMemory = MapViewOfFile(hMapFile,FILE_MAP_READ,0,0,0);在输出文件创建后我们调用MapViewOfFile来映射希望映射到内存中的部分。该函数的语法如下:LPVOID MapViewOfFile( HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap);dwDesiredAccess用来指定我们想对文件进行的操
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年二建《水利水电》练习题及答案解析
- 云南养老护理员考试题库及答案解析
- 2025新版办公室装修合同范本
- 货运从业证考试口语及答案解析
- 防诈骗安全教育答题题库及答案解析
- 银行初级从业考试选科及答案解析
- 房产中介从业资格考试及答案解析
- 交通安全知识培训 试题及答案解析
- 全民安全月题库及答案解析
- 管道安全题库及答案解析
- 2025年全国保密教育线上培训知识考试试题库有含答案
- 2025年上海科学考试题目及答案
- 试点先行人工智能+智能客服系统可行性分析
- 兵团面试题目及答案
- 2025-2030中国基建投资拉动下工程机械需求预测与市场分析
- 胰岛素泵专家共识课件
- 电梯自行检测合规指南
- 人教版(2024)八年级上册数学全册教案
- 2025年住院医师规培-新疆-新疆住院医师规培(胸心外科)历年参考题库典型考点含答案解析
- 2025年低压电工证考试题库及答案
- 足球大单元教学计划
评论
0/150
提交评论