在linux中使用記憶體對映(mmap)操作檔案的方法
在使用記憶體對映操作檔案之前,我們先按照常規的方式來讀寫檔案,這種方式操作如下:
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>
- typedefstruct{
- 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>
- typedefstruct{
- 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://blog.csdn.net/lvbian/article/details/16341973