一.内存映射文件技术作用
1.使用内存映射文件来访问磁盘上的数据文件。这使你可以不必对文件执行 I / O操作,并且可以不必对文件内容进行缓存.
2.可以使用内存映射文件,使同一台计算机上运行的多个进程能够相互之间共享数据。windows确实提供了其他一些方法,
以便在进程之间进行数据通信,但是这些方法都是使用内存映射文件来实现的,诸如使用SendMessage或者PostMessage,
都在内部使用了内存映射文件.这使得内存映射文件成为单个计算机上的多个进程互相进行通信的最有效的方法。
二.相当函数介绍
1. CreateFile函数
(1)作用:创建或打开下列对象,并返回一个可以用来访问这些对象的句柄(可以打开:文件,管道等)
(2)函数原型:
HANDLE CreateFile(
LPCTSTR lpFileName, //指向文件名的指针
DWORD dwDesiredAccess, //访问模式(写/读)
DWORD dwShareMode, //共享模式
LPSECURITY_ATTRIBUTES lpSecurityAttributes, //指向安全属性的指针
DWORD dwCreationDisposition, //如何创建
DWORD dwFlagsAndAttributes, //文件属性
HANDLE hTemplateFile //用于复制文件句柄
);
(3)参数介绍
(4)返回值
如执行成功,则返回文件句柄。INVALID_HANDLE_VALUE表示出错,会设置GetLastError。即使函数成功,
但若文件存在,且指定了CREATE_ALWAYS 或 OPEN_ALWAYS,GetLastError也会设为ERROR_ALREADY_EXISTS
2.CreateFileMapping
(1)为指定文件创建一个有名或无名的文件映象
(2)函数原型
HANDLE CreateFileMapping(
HANDLE hFile, // 映射文件的句柄
LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
// 安全描述符指针
DWORD flProtect, // 对映射对象的保护
DWORD dwMaximumSizeHigh, // 对象最大长度的高32位
DWORD dwMaximumSizeLow, // 对象最大长度的低32位
LPCTSTR lpName // 文件内存映射对象的名字
);
(3)参数说明
hFile:映射文件的句柄,文件的打开模式必须与flProtect参数指定的相一致;如果这个参数值为0xFFFFFFFF,
那么必须在dwMaximumSizeHigh和dwMaximumSizeLow参数中指定映射对象的大小。并且将在操作系统
虚拟内存页面替换文件中创建文件映射对象,而不是使用磁盘文件,同时必须给出这个映射对象的大小。
文件映射对象通过副本,遗传或名字来共享。
lpFileMappingAttributes:安全描述符指针,决定返回句柄是否能被子进程继承,如果是NULL,那么子进程不能
继承。WinNt中,如果是NULL,那么文件映射对象得到一个默认的安全描述符。
flProtect:为得到的文件试图指定保护模式,可以被设置为下列值:
PAGE_READONLY :只读属性,并且hFile对应的文件必须以GENERIC_READ形式打开。
PAGE_READWRITE:可读可写属性,并且hFile对应的文件必须以GENERIC_READ 和 GENERIC_WRITE形式打开。
PAGE_WRITECOPY:对可写区域复制后操作,并且hFile对应的文件必须以GENERIC_READ 和 GENERIC_WRITE形式打开。
dwMaximumSizeHigh,dwMaximumSizeLow:如果这两个参数为0,则文件映射对象的最大长度等于hFile指定的文件长度
lpName:文件映射对象的名字,如果这个名字已存在,则按照flProtect指定的来处理映射对象。如果此参数为空,则创
建一个无名字的文件映射对象。如果此参数的名字与系统事件的名字相同,则函数执行失败,GetLastError返回
ERROR_INVALID_HANDLE;
(4)返回值
数调用成功返回文件映射对象的句柄,如果文件映射对象已经存在则返回原有映射对象的句柄,GetLastError返回
ERROR_ALREADY_EXISTS。函数执行失败返回Null
3. MapViewOfFile
(1)在调用进程的地址空间映射一个文件视图
(2)函数原型
LPVOID MapViewOfFile(
HANDLE hFileMappingObject, // 已创建的文件映射对象句柄
DWORD dwDesiredAccess, // 访问模式
DWORD dwFileOffsetHigh, // 文件偏移的高32位
DWORD dwFileOffsetLow, // 文件偏移的低32位
DWORD dwNumberOfBytesToMap // 映射视图的大小
);
(3)参数
hFileMappingObject: 由CreateFileMapping 或 OpenFileMapping 返回的文件映射对象句柄。
dwDesiredAccess: 映射视图的访问模式,与创建文件映射对象的保护模式flProtect有关,可以被设置为下列值:
FILE_MAP_WRITE: 一个可读写属性的文件视图被创建,保护模式为PAGE_READWRITE
FILE_MAP_READ : 一个只读属性的文件视图被创建,保护模式为PAGE_READWRITE 或 PAGE_READONLY
FILE_MAP_ALL_ACCESS:与FILE_MAP_WRITE模式相同
FILE_MAP_COPY: 保护模式为PAGE_WRITECOPY时,得到一个视图文件,当你对视图文件写操作时,页面自动
交换,并且你所做的修改不会损坏原始数据资料。
dwNumberOfBytesToMap:映射文件部分的大小,如果为0,则映射整个文件。
(4)返回值:如果成功返回返回映射视图的起始地址,如果失败返回NULL
4.UnmapViewOfFile
(1)删除文件的映射视图
(2)函数原型
BOOL UnmapViewOfFile(
LPCVOID lpBaseAddress // 映射视图起始地址
);
(3)参数
lpBaseAddress:映射视图起始地址,由 MapViewOfFile 函数 MapViewOfFileEx产生
(4)返回值:如果调用成功返回非零,并且所有指定地址内的脏页面会被写入硬盘。调用失败返回零。
5.FlushViewOfFile
(1)把文件映射视图中的修改的内容或全部写回到磁盘文件中
(2)函数原型
BOOL FlushViewOfFile(
LPCVOID lpBaseAddress, // 修改内容的起始地址
DWORD dwNumberOfBytesToFlush // 修改的字节数目
);
(3)返回值:函数执行成功返回非零。
6.MapViewOfFileEx
(1)在调用进程的地址空间映射一个文件视图,并且允许调用进程为映射视图指定特殊的内存地址
(2)函数原型:
LPVOID MapViewOfFileEx(
HANDLE hFileMappingObject, // 文件映射对象的句柄
DWORD dwDesiredAccess, // 访问模式
DWORD dwFileOffsetHigh, // 文件偏移的高32位
DWORD dwFileOffsetLow, // 文件偏移的低32位
DWORD dwNumberOfBytesToMap, // 映射视图的大小
LPVOID lpBaseAddress // 指定映射视图的其实内存地址
);
注意:
与MapViewOfFile用法相同,但是如果指定的内存地址空间大小不够,则函数执行失败。
7.OpenFileMapping
(1)打开一个已命名的文件映射对象
(2)函数原型
HANDLE OpenFileMapping(
DWORD dwDesiredAccess, // 访问模式
BOOL bInheritHandle, // 继承标志
LPCTSTR lpName // 文件映射对象名指针
);
(3)参数
dwDesiredAccess:访问模式与MapViewOfFile中的访问模式相同。
bInheritHandle:继承标志,是否可以被一个新的进程继承使用,如果为TRUE,就可以被一个新进程继承句柄。
(4)返回值
成功返回一个已命名的文件映射对象,失败返回NULL。
三. 以下是简单的操作示例
#include <Windows.h>
#include <conio.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc,char argv[])
{
HANDLE hFile;
OFSTRUCT opBuf;
HANDLE hMapfile;
HANDLE hMapview;
char *recv;
//1.创建或打开文件
hFile = ::CreateFile("D:\\MapFileTest.txt", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile==0)
{
printf("open file failed!\n");
return 1;
}
//2.为指定文件创建一个有名的文件映象
hMapfile=CreateFileMapping((HANDLE)hFile,NULL,PAGE_READWRITE,0,3,"MapTest");
if(hMapfile==NULL)
{
printf("mapping file failed!\n");
return 1;
}
//关闭文件句柄
CloseHandle((HANDLE)hFile);
hFile=0;
//3.在调用进程的地址空间映射一个文件视图
hMapview=MapViewOfFile(hMapfile,FILE_MAP_WRITE,0,0,0);
if(hMapview==NULL)
{
printf("mapping view failed!\n");
return 1;
}
//往文件映射视图中写入数据
recv=(char *)hMapview;
printf("Mapping view's content is :%.10s \n",recv);
strcpy(recv,"abc");
//把文件映射视图中的修改的内容或全部写回到磁盘文件中
FlushViewOfFile(recv,3);
//4.删除文件的映射视图
printf("Mapping view's content is :%.10s \n",recv);
UnmapViewOfFile(hMapview);
//关闭文件映象句柄
CloseHandle(hMapfile);
hMapfile = 0;
_getch();
return 0;
}