函数mmap()将某个文件的指定内容映射到内存空间中,从而提供不同与一般的普通文件操作方式,进程可以像读写内存一样对普通文件进行操作。普通文件被映射到进程地址空间后,进程可以像访问普通内存一样对文件进行访问,不必再调用read,write等操作。简单地说,就是把一个文件的内容在内存里做一个映像,加快访问速度。函数声明如下:
1 #include <sys/mman.h> 2 void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset)
此函数将在进程的虚拟地址空间(起始为start,长度为len字节)和与文件描述符fd关联的文件(偏移为offset,长度为length字节)之间建立映射。
第1个参数为映射的特定地址,当然,一般情况下设置为NULL,由系统分配。
第2个参数为映射的文件长度。
第3个参数prot描述映射的内存权限(不得与该文件的打开权限冲突),该参数是一下选项的组合:
PROT_READ: 允许读该内存段
PROT_WRITE: 允许写该内存段
PROT_EXEC: 允许执行该内存段
PROT_NONE: 该内存段不能被访问
第4个参数flags控制程序对该内存段的改变所造成的影响。常用选项如下:
MAP_PRIVATE: 内存段是私有的,对它的修改只在局部范围内有效,其他进程不可见。
MAP_SHARED: 共享映射。某进程对该段内存空间的更新对其他进程来说是可见的,但与之关联的该文件的内容并不会立即更新,要更新文件内容,需要调用msync()和munmap()函数。
这个flags参数还有其他一些值,具体可以查mmap()函数的man手册。
第5个参数为映射的文件描述符。
第6个参数为偏移,即要映射的内容在文件中的起始位置。
如果要解除映射,可以调用munmap()函数,相应的修改内容将回写到文件中,此函数声明如下:
1 int munmap(void* start,size_t length)
如果希望立即将更新写入文件中,可以调用msync()函数,声明如下:
1 int msync(const void* start,size_t length,int flags)
start为内存的开始位置,length为长度。flags选项如下:
MS_ASYNC: 请内核尽快将资料写入文件中
MS_SYNC: 在此函数结束返回前将资料写入文件。
MS_INVALIDATE: 让内核自行决定是否写入,仅在特殊状况下使用。
以下是映射文件到内存,并打印出来的示例代码:
1 #include <iostream> 2 #include <stdio.h> 3 #include <memory.h> 4 #include <sys/mman.h> 5 #include <sys/types.h> 6 #include <sys/stat.h> 7 #include <fcntl.h> 8 #include <unistd.h> 9 using namespace std; 10 11 int main(int argc,char* argv[]) 12 { 13 int fd; 14 char *mapped_mem,*p; 15 int flength=1024; 16 void* start_addr=0; 17 fd=open(argv[1],O_RDWR|O_CREAT,S_IRUSR|S_IWUSR); //打开文件 18 flength=lseek(fd,0,SEEK_END); //求文件长度 同时文件指针移动到了文件尾 19 cout<<"flength: "<<flength<<endl; 20 lseek(fd,0,SEEK_SET); //将文件指针设置到文件开始位置 21 mapped_mem=(char*)mmap(start_addr,flength,PROT_READ|PROT_WRITE,MAP_PRIVATE,fd,0); //执行映射 22 *(mapped_mem+flength)='\0'; //加个\0便于使用%s输出 注意这里,如果上面mmap函数参数没有设置PROT_WRITE,那么这里是不可写的。 23 int len=strlen(mapped_mem); 24 cout<<"len: "<<len<<endl; 25 printf("%s\n",mapped_mem); //打印内容 26 close(fd); 27 munmap(mapped_mem,flength); //解除映射 28 return 0; 29 }