1. 程式人生 > >在linux中使用記憶體對映(mmap)操作檔案的方法

在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. <strong>//寫記憶體到檔案</strong>
  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. typedefstruct{  
  7.     char name[20];  
  8.     short age;  
  9.     float score;  
  10.     char sex;  
  11. }Student;  
  12. <strong>//讀取檔案到記憶體</strong>
  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. typedefstruct{  
  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. }  
  64. 轉:http://blog.csdn.net/lvbian/article/details/16341973