红联Linux门户
Linux帮助

在linux中使用内存映射(mmap)操作文件

发布时间:2016-02-24 09:50:51来源:linux网站作者:积江流成大海

在使用内存映射操作文件之前,我们先按照常规的方式来读写文件,这种方式操作如下:

1,打开或创建文件,得到文件描述符,

2,将内存中的数据以一定的格式和顺序写入文件,或者将文件中的数据以一定的格式和顺序读入到内存;

3,关闭文件描述符;


下边是按照常规方式操作固定格式的文件的方法,包含读写两个示例;

#include <stdlib.h> 
#include <stdio.h> 
#include <unistd.h> 
#include <fcntl.h> 
#include <string.h> 
<strong>//写内存到文件</strong> 
struct student{ 
char name[20]; 
short age; 
float score; 
char sex; 
}; 
int main() 

struct student stu[5]; 
mode_t mode; 
mode=umask(000);  
int fd=open("user.dat",O_RDWR|O_CREAT|O_EXCL,00666); 
if(fd==-1){ 
printf("open:%m\n"); 
umask(mode); 
exit(-1); 

printf("ok\n"); 
memset(stu,0,sizeof(stu));
int i=0; 
for(;i<5;i++){ 
memcpy(stu[i].name,"tom",strlen("tom")+1); 
stu[i].age=i; 
stu[i].score=89.12f; 
stu[i].sex='m'; 
write(fd,&stu[i],sizeof(stu[i]));

close(fd); 
umask(mode); 
return 0;


#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <fcntl.h> 
#include <string.h> 

typedef struct{ 
char name[20]; 
short age; 
float score; 
char sex; 
}Student; 
<strong>//读取文件到内存</strong> 
int main() 

Student stu[5]; 
mode_t mode; 
mode=umask(0000); 
int fd=open("user.dat",O_RDWR,0666); 
if(fd==-1){ 
printf("open:%m\n"); 
umask(mode); 
exit(-1);

printf("open ok! can read;\n"); 
int i=0; 
for(;i<5;i++){ 
read(fd,&stu[i],sizeof(stu[i])); 

close(fd); 
i=0; 
for(;i<5;i++){ 
printf("stu[%d].name=%s\n",i,stu[i].name); 
printf("stu[%d].age=%d\n",i,stu[i].age); 
printf("stu[%d].sex=%c\n",i,stu[i].sex); 
printf("stu[%d].score=%f\n",i,stu[i].score); 

umask(mode); 
return 0; 


以上操作文件的方式只能操作小文件,如果文件很大,就无法一次载入内存操作,我们就需要用到内存映射技术来操作;具体实现如下:


1,首先打开文件,使用的函数原型如下:

int open(  //返回值:大于等于0代表操作成功,返回打开的文件描述符号,=-1,创建或者打开失败,失败可查阅errorno来获取具体错误信息

const char *pathname,   //要打开的文明名

int flags, //打开的方式,打开方式包括:O_RDONLY 只读方式 O_WRONLY 只写,O_RDWR读写,O_CREAT创建,O_EXCL文件如果存在,使用此标记,会返回错误

mode_t mode); //指定创建文件的权限,只对创建文件有效,对于打开无效;


2,获取文件大小

int fstat(int fd,//文件描述符号

struct stat*buf);//返回文件属性结构体

返回值:成功返回0;失败返回-1


3,把文件映射成虚拟内存

void *mmap(void *addr,  //从进程的那个地址开始映射,如果为NULL,由系统指定;

size_t length, //映射的地址空间的大小

int prot, //内存的保护模式

int flags,//映射模式 有匿名,私有,保护等标记 具体查询man手册;

int fd,  //如果为文件映射,则此处为文件的描述符号

off_t offset);//如果为文件映射,则此处代表定位到文件的那个位置,然后开始向后映射。

返回值:映射成功,返回首地址;


4,通过对内存的读写来实现对文件的读写

通常使用:memset 和memcpy来实现操作;


5,卸载映射

int munmap(void *addr,  //要卸载的内存的地址

size_t length);//内存的大小


6,关闭文件

int close(int fd);  //要关闭的文件描述符号  ,成功返回0,错误返回-1,错误参照errorno;


下边是读取文件的操作:

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <fcntl.h> 
#include <sys/mman.h> 
#include <sys/stat.h> 
typedef struct{ 
char name[20]; 
short age; 
float score; 
char sex; 
}student; 
int main() 

student *p,*pend;
//打开文件描述符号 
int fd; 
/*打开文件*/ 
fd=open("user.dat",O_RDWR); 
if(fd==-1){//文件不存在 
fd=open("user.dat",O_RDWR|O_CREAT,0666); 
if(fd==-1){ 
printf("打开或创建文件失败:%m\n"); 
exit(-1); 


//打开文件ok,可以进行下一步操作 
printf("open ok!\n");
//获取文件的大小,映射一块和文件大小一样的内存空间,如果文件比较大,可以分多次,一边处理一边映射; 
struct stat st; //定义文件信息结构体 
/*取得文件大小*/ 
int r=fstat(fd,&st); 
if(r==-1){ 
printf("获取文件大小失败:%m\n"); 
close(fd); 
exit(-1); 

int len=st.st_size; 
/*把文件映射成虚拟内存地址*/ 
p=mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); 
if(p==NULL || p==(void*)-1){ 
printf("映射失败:%m\n"); 
close(fd); 
exit(-1); 

/*定位到文件开始*/ 
pend=p;  
/*通过内存读取记录*/ 
int i=0; 
while(i<(len/sizeof(student))) 

printf("第%d个条\n",i); 
printf("name=%s\n",p[i].name); 
printf("age=%d\n",p[i].age); 
printf("score=%f\n",p[i].score); 
printf("sex=%c\n",p[i].sex); 
i++; 
}
/*卸载映射*/ 
munmap(p,len); 
/*关闭文件*/ 
close(fd); 
}


本文永久更新地址:http://www.linuxdiyf.com/linux/18344.html