存储映射 I/O 使一个磁盘文件与存储空间中的一个缓冲区相映射。于是从缓冲区中取数据,就相当于读文件的相应字节,同理,将数据写入缓冲区,则相应字节就会自动写入文件。这样可以不使用 read 和 write 函数的情况下执行 I/O。
将一个给定的文件映射到缓冲区可以使用 mmap 函数;
/* 存储映射IO */ /* * 函数功能:将一个给定文件映射到存储区域中; * 返回值:若成功则返回缓冲区的起始地址,若出错则返回MAP_FAILED; * 函数原型: */ #include <sys/mman.h> void *mmap(void *addr, size_t len, int prot, int flag, int filedes, off_t off); /* * 说明: * addr参数用于指定映射存储区的起始地址,通常将其设置为0,这样由系统自动分配起始地址; * filedes指定要被映射文件的描述符,在映射之前,先要打开该文件; * len是映射的字节数; * off是要映射字节在文件中的起始偏移量; * prot是对映射存储区的保护要求,具体参数是以下的按位"或"组合: * PROT_READ 映射区可读 * PROT_WRITE 映射区可写 * PROT_EXEC 映射区可执行 * PROT_NONE 映射区不可访问 * * flag参数影响映射存储区的多重属性: * MAP_FIXED 返回值必须等于addr; * MAP_SHARED 说明本进程对映射区所进行的存储操作的配置;指定存储操作修改映射文件; * MAP_PRIVATE 对映射区的存储操作导致创建该映射文件的一个私有副本,所有后来对映射区的引用都是该副本; */
调用 mprotect 可以更改一个现有映射存储区的权限:
/* * 函数功能:更改一个现有映射存储区的权限; * 返回值:若成功则返回0,若出错则返回-1; * 函数原型: */ #include <sys/mman.h> int mprotect(void *addr, size_t len, int prot); /* * 说明: * 参数prot和mmap函数的参数一样; * 起始地址addr必须是系统页长的整数倍; */
/* * 函数功能:将页冲洗到被映射的文件中; * 返回值:若成功则返回0,若出错则返回-1; * 函数原型: */ #include <sys/mman.h> int msync(void *addr, size_t len, int flags); /* * 说明: * 若映射是私有的,则不修改被映射的文件,地址必须与页边界对齐; * 参数flags取值如下: * MS_ASYNC 执行异步写 * MS_SYNC 执行同步写 * MS_INVALIDATE 使高速缓存的数据失效 */
/* * 函数功能:解除映射存储区; * 返回值:若成功则返回0,若出错则返回-1; * 函数原型: */ #include <sys/mman.h> int munmap(void *addr, size_t len);munmap 不会影响被映射的对象,也就是说,调用 munmap 不会使映射区的内容写到磁盘文件上。对于 MAP_SHARED 区磁盘文件的更新,在写到存储映射区时按内核虚拟内存算法自动进行,在解除了映射后,对于 MAP_PRIVATE 存储区的修改被丢弃。
测试程序:
#include "apue.h" #include <sys/mman.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> int main(int argc, char **argv) { int fd; void *dst; struct stat f_stat; char buf[MAXLINE]; memset(buf, 0, MAXLINE); char *src = "mmap munmap msync 12"; if(argc != 2) err_quit("usage: a.out <pathname>"); if((fd = open(argv[1], O_RDWR)) < 0) err_sys("open argv[1] file error"); if(fstat(fd, &f_stat) == -1 ) err_sys("fstat error"); if((dst = mmap(NULL, f_stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) err_sys("mmap error"); close(fd); memcpy(dst, src, 20); if((msync(dst, f_stat.st_size, MS_SYNC)) == -1) err_sys("msync error"); if((munmap(dst, f_stat.st_size)) == -1) err_sys("munmap error"); exit(0); }
原始文件mmap.txt 里面的内容为:
cat mmap.txt cccccccccccccccccc ffffffffffffffffff eeeeeeeeeeeeeeeeee yyyyyyyyyyyyyyyyyy qqqqqqqqqqqqqqqqqq aaaaaaaaaaaaaaaaaa pppppppppppppppppp vvvvvvvvvvvvvvvvvv zzzzzzzzzzzzzzzzzz xxxxxxxxxxxxxxxxxx
映射存储之后的内容为:
mmap munmap msync 12 fffffffffffffffff eeeeeeeeeeeeeeeeee yyyyyyyyyyyyyyyyyy qqqqqqqqqqqqqqqqqq aaaaaaaaaaaaaaaaaa pppppppppppppppppp vvvvvvvvvvvvvvvvvv zzzzzzzzzzzzzzzzzz xxxxxxxxxxxxxxxxxx输出结果:注意:以下是mmap以共享模式的即MAP_SHARED,若是以私有模式的并不会修改源文件
$cat mmap.txt cccccccccccccccccc ffffffffffffffffff eeeeeeeeeeeeeeeeee yyyyyyyyyyyyyyyyyy qqqqqqqqqqqqqqqqqq aaaaaaaaaaaaaaaaaa pppppppppppppppppp vvvvvvvvvvvvvvvvvv zzzzzzzzzzzzzzzzzz xxxxxxxxxxxxxxxxxx $ ./mmap mmap.txt $ cat mmap.txt mmap munmap msync 12 fffffffffffffffff eeeeeeeeeeeeeeeeee yyyyyyyyyyyyyyyyyy qqqqqqqqqqqqqqqqqq aaaaaaaaaaaaaaaaaa pppppppppppppppppp vvvvvvvvvvvvvvvvvv zzzzzzzzzzzzzzzzzz xxxxxxxxxxxxxxxxxx
《UNIX高级环境编程》