Linux下内存映射文件的用法
学习了一下Linux下内存映射文件的用法,在这里共享一下自己的收获,希望大家提出宝贵意见,进行交流。 简介: 内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区域,同时将物理存储器提交给此区域,只是内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而非系统的页文件,而且在对该文件进行操作之前必须首先对文件进行映射,就如同将
简介:
内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区域,同时将物理存储器提交给此区域,只是内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而非系统的页文件,而且在对该文件进行操作之前必须首先对文件进行映射,就如同将整个文件从磁盘加载到内存。由此可以看出,使用内存映射文件处理存储于磁盘上的文件时,将不必再对文件执行I/O操作,这意味着在对文件进行处理时将不必再为文件申请并分配缓存,所有的文件缓存操作均由系统直接管理,由于取消了将文件数据加载到内存、数据从内存到文件的回写以及释放内存块等步骤,使得内存映射文件在处理大数据量的文件时能起到相当重要的作用。另外,实际工程中的系统往往需要在多个进程之间共享数据,如果数据量小,处理方法是灵活多变的,如果共享数据容量巨大,那么就需要借助于内存映射文件来进行。实际上,内存映射文件正是解决本地多个进程间数据共享的最有效方法。
Linux提供了内存映射函数mmap, 它把文件内容映射到一段内存上(准确说是虚拟内存上), 通过对这段内存的读取和修改, 实现对文件的读取和修改, 先来看一下mmap的函数声明:
- 头文件:
- <unistd.h>
- <sys/mman.h>
- 原型: void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offsize);
- 返回值: 成功则返回映射区起始地址, 失败则返回MAP_FAILED(-1).
- 参数:
- addr: 指定映射的起始地址, 通常设为NULL, 由系统指定.
- length: 将文件的多大长度映射到内存.
- prot: 映射区的保护方式, 可以是:
- PROT_EXEC: 映射区可被执行.
- PROT_READ: 映射区可被读取.
- PROT_WRITE: 映射区可被写入.
- PROT_NONE: 映射区不能存取.
- flags: 映射区的特性, 可以是:
- MAP_SHARED: 对映射区域的写入数据会复制回文件, 且允许其他映射该文件的进程共享.
- MAP_PRIVATE: 对映射区域的写入操作会产生一个映射的复制(copy-on-write), 对此区域所做的修改不会写回原文件.
- 此外还有其他几个flags不很常用, 具体查看linux C函数说明.
- fd: 由open返回的文件描述符, 代表要映射的文件.
- offset: 以文件开始处的偏移量, 必须是分页大小的整数倍, 通常为0, 表示从文件头开始映射.
下面说一下内存映射的步骤:
- 用open系统调用打开文件, 并返回描述符fd.
- 用mmap建立内存映射, 并返回映射首地址指针start.
- 对映射(文件)进行各种操作, 显示(printf), 修改(sprintf).
- 用munmap(void *start, size_t lenght)关闭内存映射.
- 用close系统调用关闭文件fd.
注意事项:
在修改映射的文件时, 只能在原长度上修改, 不能增加文件长度, 因为内存是已经分配好的.
在网上找了一些代码,自己加工之后在Linux下编译通过,可以运行实现相应功能。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<errno.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/mman.h>
int main()
{
int outfile;
char*mapped;
char*ptr;
if((outfile=open("test.dat",O_RDWR|O_CREAT|O_TRUNC,0640))==-1)
{
printf("couldn't open this file!\n");
exit(254);
}
lseek(outfile,1000,SEEK_SET);//把文件指针outfile移到从文件头开始到1000字节处
if(write(outfile,"\0",1)==-1)//在第1001字节处写入数据"\0"
{
printf("error,write failed!\n");
exit(254);
}
//创建内存映像文件,将文件从文件头开始到1000字节处映射到内存,mapped指向该内存的首地址
mapped=mmap(NULL,1000,PROT_READ|PROT_WRITE,MAP_SHARED,outfile,0);
if(!mapped)
{
printf("error ,write failed!\n");
exit(254);
}
ptr=mapped;
printf("please enter a number!\n");
fgets(mapped,80,stdin);//从终端输入一个数字
printf("your number times two is:%d\n",atoi(mapped)*2);
//将该数字与2相乘结果打印出来
sprintf(ptr,"your number timews two is :%d\n",atoi(mapped)*2);//把数据保存到内存中
msync(ptr,1000,MS_SYNC);//将内存中数据保存到文件中
munmap(ptr,1000); //撤销内存映像文件
if(close(outfile))
{
printf("possibly serious error,close file failed!\n");
exit(254);
}
return 0;
}
更多推荐
所有评论(0)