C语言-内存映射是什么,根据自己粗浅的学习理解,总结为—— 创建一个文件映射内核对象然,然后在把文件映射内核对象映射到内存地址空间中,然后我们拿这个内存地址(也就是无类型类型指针)对内存空间(也就相当与硬盘上的文件)进行操作了。
这里面包含了三大内容(内村指针就不介绍了):文件打开或创建、文件映射内核对象,映射文件映射到内存地址空间
CreateFile 函数用于创建或打开文件、pipes、邮槽 、通信资源、磁盘驱动器(仅适用于 windowsNT )、控制台 、文件夹(仅用于打开)对象,并返回一个可以用来访问这些对象的句柄。在这里我们只用打开或创建文件。
函数原型:HANDLE CreateFile(
LPCTSTR lpFileName, // 指向文件名的指针
DWORD dwDesiredAccess, // 访问模式(写 / 读)
DWORD dwShareMode, // 共享模式
LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 指向安全属性的指针
DWORD dwCreationDisposition, // 如何创建
DWORD dwFlagsAndAttributes, // 文件属性
HANDLE hTemplateFile // 用于复制文件句柄
);
样例:
#include
#include
int main(){
//创建文件
HANDLE hFile = CreateFile((LPCSTR)FileName, //文件目录包含文件名
GENERIC_WRITE | GENERIC_READ, //访问模式为读写方式
FILE_SHARE_READ | FILE_SHARE_WRITE, //共享模式读写方式
NULL, //句柄不可继承
OPEN_ALWAYS, //如果文件存在,打开则,不覆盖.如果不存在 则创建.
FILE_FLAG_SEQUENTIAL_SCAN, //针对连续访问对文件缓冲进行优化.
NULL //);
if (hFile == INVALID_HANDLE_VALUE) {
printf("1-创建文件失败,错误代码:%d ", GetLastError());
}
CloseHandle(hFile); //关闭文件
system("pause");
return 0;
}
内核对象是系统提供的用户模式下代码与内核模式下代码进行交互的基本接口。
作为一个软件开发人员,你经常需要创建、打开和操作各种内核对象。系统要创建和操作若干类型的内核对象,比如存取符号对象、事件对象、文件对象、文件映射对象、I/O完成端口对象、作业对象、信箱对象、互斥对象、管道对象、进程对象、信标对象、线程对象和等待计时器对象等。这些对象都是通过调用函数来创建的。
CreateFileMapping 函数用于创建一个文件映射内核对象。
函数原型:HANDLE CreateFileMapping(
HANDLE hFile, //物理文件句柄
LPSECURITY_ATTRIBUTES lpAttributes, //安全设置
DWORD flProtect, //保护设置
DWORD dwMaximumSizeHigh, //高位文件大小
DWORD dwMaximumSizeLow, //低位文件大小
LPCTSTR lpName //共享内存名称
);
样例:
#include
#include
int main(){
//创建文件
HANDLE hFile = CreateFile((LPCSTR)FileName, //文件目录包含文件名
GENERIC_WRITE | GENERIC_READ, //访问模式为读写方式
FILE_SHARE_READ | FILE_SHARE_WRITE, //共享模式读写方式
NULL, //句柄不可继承
OPEN_ALWAYS, //如果文件存在,打开则,不覆盖.如果不存在 则创建.
FILE_FLAG_SEQUENTIAL_SCAN, //针对连续访问对文件缓冲进行优化.
NULL //);
if (hFile == INVALID_HANDLE_VALUE) {
printf("1-创建文件失败,错误代码:%d ", GetLastError());
}
####################################本节案例代码####################################
//创建文件映射对象
HANDLE hFileMap = CreateFileMapping(hFile, //文件句柄(CreateFile返回的文件句柄)
NULL, //默认的安全配置
PAGE_READWRITE, //容许读和写
NULL, //大于4G时有用
NULL, //文件大小(新建文件时不能为0,会报10016错误)
nullptr //互斥句柄);
if (hFileMap == NULL)
{
printf("2-创建文件映射内核对象失败,错误代码:%d ", GetLastError());
}
########################################结束########################################
CloseHandle(hFile); //关闭文件
CloseHandle(hFileMap); //关闭文件映射
system("pause");
return 0;
}
3、映射文件映射到内存地址空间 MapViewOfFile
内存地址空间我也没理解附上几个链接再次:内存地址与内存空间:https://www.cnblogs.com/Lanht/p/10780364.html内存地址空间:https://www.cnblogs.com/lazyli/p/10923909.html
MapViewOfFile 函数是将一个文件映射对象映射到当前应用程序的地址空间
函数原型:HANDLE CreateFileMapping(
__in HANDLE hFileMappingObject, //文件映像对象句柄
__in DWORD dwDesiredAccess, //映射对象的文件数据的访问方式
__in DWORD dwFileOffsetHigh, //文件映射起始偏移的高32位
__in DWORD dwFileOffsetLow, //文件映射起始偏移的低32位
__in SIZE_T dwNumberOfBytesToMap //指定映射文件的字节数
);
#include
#include
int main(){
//创建文件
HANDLE hFile = CreateFile((LPCSTR)FileName, //文件目录包含文件名
GENERIC_WRITE | GENERIC_READ, //访问模式为读写方式
FILE_SHARE_READ | FILE_SHARE_WRITE, //共享模式读写方式
NULL, //句柄不可继承
OPEN_ALWAYS, //如果文件存在,打开则,不覆盖.如果不存在 则创建.
FILE_FLAG_SEQUENTIAL_SCAN, //针对连续访问对文件缓冲进行优化.
NULL //);
if (hFile == INVALID_HANDLE_VALUE) {
printf("1-创建文件失败,错误代码:%d ", GetLastError());
}
//创建文件映射对象
HANDLE hFileMap = CreateFileMapping(hFile, //文件句柄(CreateFile返回的文件句柄)
NULL, //默认的安全配置
PAGE_READWRITE, //容许读和写
NULL, //大于4G时有用
NULL, //文件大小(新建文件时不能为0,会报10016错误)
nullptr //互斥句柄);
if (hFileMap == NULL)
{
printf("2-创建文件映射内核对象失败,错误代码:%d ", GetLastError());
}
CloseHandle(hFile); //关闭文件
####################################本节案例代码####################################
// 文件映射内核对象映射到当前应用程序的地址空间
LPVOID lpbMapAddress = MapViewOfFile(hFileMap, //文件映像对象句柄
FILE_MAP_ALL_ACCESS, //读和写
0, //大于4G指针偏移量
0, //小于4G指针偏移量
0 //文件大小(不能大于文件映射对象的大小,否则报错,网上没有找的书可以用0,但我这里写0可以正常使用。
);
if (lpbMapAddress == NULL)
{
printf("3-映射文件映射内核对象失败,错误代码:%d ", GetLastError());
CloseHandle(hFileMap);
return 0;
}
CloseHandle(hFileMap); //关闭文件映射
########################################结束########################################
system("pause");
return 0;
}
到此位置我们的文件就映射到 我类型的lpbMapAddress 指针上了内存大小为我们创建的CreateFileMapping时填的大小,可以像普通无类型指针一样 操作了。
创建或打开的文件句柄在创建完文件映射对象句柄后就可以关闭了,文件映射对象句柄在创建完内存映射后也可以关闭,但有时后期还要用到它,最好不要关闭,到程序结束时再关闭。句柄何时关闭,刚接触是也是很迷糊,经过测试得出了结论。所以在这再唠叨几句。记得最后还要关闭内存映射UnMapViewOfFile(lpbMapAddress )。