内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用read,write等系统调用函数。
mmap函数:函数原型
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
addr:人为指定映射的起始虚拟地址
设置为NULL,表示由内核决定映射的起始虚拟地址,这也是最常见的设置方式
设置不为NULL,就表示由自己指定,指定的起始虚拟地址必须是虚拟页(4k)的整数倍
length:映射长度,也就是你想对文件映射多长
prot:指定对映射区的操作权限
PROT_EXEC:映射区的内容可执行
PROT_READ:映射区的内容可读
PROT_WRITE:映射区的内容可写
PROT_NONE:映射区不允许访问(不允许执行、读、写),一般不会指定这个
flags:向映射区写入了数据,是否将数据立即更新到文件中
MAP_SHARED:立即更新
fd:需要被映射文件的描述符
offset:表示从文件头的offset处开始映射,一般都指定为0,表示从文件头开始映
返回值:
调用成功,返回映射的起始虚拟地址,失败则返回(void*)NULL,errno被设置。
---------------------------------------------------------------------------------------------------------------------------------
munmap函数原型 -- 取消存储映射
int munmap(void *addr, size_t length);
addr:映射的起始虚拟地址
length:需要取消的长度
返回值:
调用成功返回0, 失败则-1, errno被设置
---------------------------------------------------------------------------------------------------------------------------------
代码示例:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
int fd = open(argv[1], O_RDWR | O_CREAT, 0655);
struct stat file;
ftruncate(fd, 1); // 如果是新打开的文件,文件大小为0,导致映射的空间为0,可能会发生段错误。
fstat(fd, &file); // 获得文件属性
void *addr = mmap(NULL, file.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (addr == NULL)
{
perror("mmap error:");
}
char buffer[1024] = "hello world";
ftruncate(fd, strlen(buffer)); // 将文件截断为制定长度 (扩容)
strcpy(addr, buffer); // 从前往后覆盖
memset(buffer, 0, sizeof(buffer));
strncpy(buffer, addr, sizeof(buffer) - 1);
printf("buffer = %s\n", buffer);
/******************************************************************/
munmap(addr, file.st_size);
close(fd);
return 0;
}
运行结果:
superlan@GodFather:~/C_Language/advanced_IO_operation$ ./a.out hello.txt
buffer = hello world
存储映射应用场合:
将一个普通文件映射到内存中,通常在需要对文件进行频繁读写时使用,这样用内存读写取代I/O读写,以获得较高的性能;
将特殊文件进行匿名内存映射,可以为关联进程提供共享内存空间;
为无关联的进程提供共享内存空间,一般也是将一个普通文件映射到内存中。