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

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

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

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

3,关闭文件描述符;

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

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. #include <fcntl.h>
  5. #include <string.h>
  6. //写内存到文件
  7. struct student{
  8. char name[ 20];
  9. short age;
  10. float score;
  11. char sex;
  12. };
  13. int main()
  14. {
  15. struct student stu[5];
  16. mode_t mode;
  17. mode=umask( 000);
  18. int fd=open( "user.dat",O_RDWR|O_CREAT|O_EXCL, 00666);
  19. if(fd== -1){
  20. printf( "open:%m\n");
  21. umask(mode);
  22. exit( -1);
  23. }
  24. printf( "ok\n");
  25. memset(stu, 0, sizeof(stu));
  26. int i= 0;
  27. for(;i< 5;i++){
  28. memcpy(stu[i].name, "tom", strlen( "tom")+ 1);
  29. stu[i].age=i;
  30. stu[i].score= 89.12f;
  31. stu[i].sex= 'm';
  32. write(fd,&stu[i], sizeof(stu[i]));
  33. }
  34. close(fd);
  35. umask(mode);
  36. return 0;
  37. }
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <fcntl.h>
  5. #include <string.h>
  6. typedef struct{
  7. char name[ 20];
  8. short age;
  9. float score;
  10. char sex;
  11. }Student;
  12. //读取文件到内存
  13. int main()
  14. {
  15. Student stu[ 5];
  16. mode_t mode;
  17. mode=umask( 0000);
  18. int fd=open( "user.dat",O_RDWR, 0666);
  19. if(fd== -1){
  20. printf( "open:%m\n");
  21. umask(mode);
  22. exit( -1);
  23. }
  24. printf( "open ok! can read;\n");
  25. int i= 0;
  26. for(;i< 5;i++){
  27. read(fd,&stu[i], sizeof(stu[i]));
  28. }
  29. close(fd);
  30. i= 0;
  31. for(;i< 5;i++){
  32. printf( "stu[%d].name=%s\n",i,stu[i].name);
  33. printf( "stu[%d].age=%d\n",i,stu[i].age);
  34. printf( "stu[%d].sex=%c\n",i,stu[i].sex);
  35. printf( "stu[%d].score=%f\n",i,stu[i].score);
  36. }
  37. umask(mode);
  38. return 0;
  39. }

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

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;

下边是读取文件的操作:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <fcntl.h>
  5. #include <sys/mman.h>
  6. #include <sys/stat.h>
  7. typedef struct{
  8.   char name[20];
  9.   short age;
  10.   float score;
  11.   char sex;
  12. }student;
  13. int main()
  14. {
  15.   student *p,*pend;  
  16.   //打开文件描述符号
  17.   int fd;
  18.   /*打开文件*/
  19.     fd=open("user.dat",O_RDWR);
  20.     if(fd==-1){//文件不存在
  21.         fd=open("user.dat",O_RDWR|O_CREAT,0666);
  22.         if(fd==-1){
  23.             printf("打开或创建文件失败:%m\n");
  24.             exit(-1);
  25.         }
  26.     }
  27.   //打开文件ok,可以进行下一步操作
  28.   printf("open ok!\n");  
  29.   //获取文件的大小,映射一块和文件大小一样的内存空间,如果文件比较大,可以分多次,一边处理一边映射;
  30.   struct stat st; //定义文件信息结构体
  31.   /*取得文件大小*/
  32.   int r=fstat(fd,&st);
  33.   if(r==-1){
  34.       printf("获取文件大小失败:%m\n");
  35.       close(fd);
  36.       exit(-1);
  37.   }
  38.   int len=st.st_size;    
  39.   /*把文件映射成虚拟内存地址*/
  40.   p=mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);    
  41.   if(p==NULL || p==(void*)-1){
  42.       printf("映射失败:%m\n");
  43.       close(fd);
  44.       exit(-1);
  45.   }
  46.   /*定位到文件开始*/
  47.   pend=p;
  48.   /*通过内存读取记录*/
  49.   int i=0;
  50.   while(i<(len/sizeof(student)))
  51.   {
  52.     printf("第%d个条\n",i);
  53.     printf("name=%s\n",p[i].name);
  54.     printf("age=%d\n",p[i].age);
  55.     printf("score=%f\n",p[i].score);
  56.     printf("sex=%c\n",p[i].sex);
  57.     i++;
  58.   }  
  59.   /*卸载映射*/
  60.   munmap(p,len);
  61.   /*关闭文件*/    
  62.   close(fd);    
  63. }

猜你喜欢

转载自blog.csdn.net/Windgs_YF/article/details/80856458