四、存储映射I/O
存储映射I/O使一个磁盘文件与存储空间中的一个缓冲区相映射。于是当从缓冲区中取数据,就相当于读文件中的相应字节。与此类似,将数据存入缓冲区,则相应字节自动地写入文件。这样就可以在不使用read和write的情况下执行I/O。
6.
名称:: |
mmap |
功能: |
把I/O文件映射到一个存储区域中 |
头文件: |
#include <sys/mman.h> |
函数原形: |
void *mmap(void *addr,size_t len,int prot,int flag,int filedes,off_t off); |
参数: |
addr 指向映射存储区的起始地址 len 映射的字节 prot 对映射存储区的保护要求 flag flag标志位 filedes 要被映射文件的描述符 off 要映射字节在文件中的起始偏移量 |
返回值: |
若成功则返回映射区的起始地址,若出错则返回MAP_FAILED |
addr参数用于指定映射存储区的起始地址。通常将其设置为0,这表示由系统选择该映射区的起始地址。
filedes指要被映射文件的描述符。在映射该文件到一个地址空间之前,先要打开该文件。len是映射的字节数。
off是要映射字节在文件中的起始偏移量。通常将其设置为0。
prot参数说明对映射存储区的保护要求。可将prot参数指定为PROT_NONE,或者是PROT_READ(映射区可读),PROT_WRITE(映射区可写),PROT_EXEC(映射区可执行)任意组合的按位或,也可以是PROT_NONE(映射区不可访问)。对指定映射存储区的保护要求不能超过文件open模式访问权限。
flag参数影响映射区的多种属性:
MAP_FIXED 返回值必须等于addr.因为这不利于可移植性,所以不鼓励使用此标志。
MAP_SHARED 这一标志说明了本进程对映射区所进行的存储操作的配置。此标志指定存储操作修改映射文件。
MAP_PRIVATE 本标志导致对映射区建立一个该映射文件的一个私有副本。所有后来对该映射区的引用都是引用该副本,而不是原始文件。
要注意的是必须指定MAP_FIXED或MAP_PRIVATE标志其中的一个,指定前者是对存储映射文件本身的一个操作,而后者是对其副本进行操作。
7.
名称:: |
memcpy |
功能: |
复制映射存储区 |
头文件: |
#include <string.h> |
函数原形: |
void *memcpy(void *dest,const void *src,size_t n); |
参数: |
dest 待复制的映射存储区 src 复制后的映射存储区 n 待复制的映射存储区的大小 |
返回值: |
返回dest的首地址 |
memcpy拷贝n个字节从dest到src。
8.
名称:: |
munmap |
功能: |
解除存储映射 |
头文件: |
#include <sys/mman.h> |
函数原形: |
int munmap(caddr_t addr,size_t len); |
参数: |
addr 指向映射存储区的起始地址 len 映射的字节 |
返回值: |
若成功则返回0,若出错则返回-1 |
进程终止时,或调用了munmap之后,存储映射区就被自动解除映射。关闭文件描述符filedes并不解除映射区。
munmap不会影响被映射的对象。
下面就是利用上面的两个函数实现的第二个版本的cp命令。
/*12_5.c*/ #include <unistd.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/stat.h> #include <sys/types.h>
int main(int argc,char *argv[]) { int fdin,fdout; void *arc,dst; struct stat statbuf;
if(argc!=3) { printf(“please input two file!\n”); exit(1); } if((fdin=open(argv[1],O_RDONLY))<0) /*打开原文件*/ perror(argv[1]); if((fdout=open(argv[2],O_RDWR|O_CREAT|O_TRUNC))<0)/*创建并打开目标文件*/ perror(argv[2]);
if(fstat(fdin,&statbuf)<0) /*获得文件大小信息*/ printf(“fstat error”);
if(lseek(fdout,statbuf.st_size-1,SEEK_SET)==-1)/*初始化输出映射存储区*/ printf(“lseek error”); if(write(fdout,””1)!=1) printf(“write error”);
if((src=mmap(0,statbuf.st_size,PROT_READ,MAP_SHARED,fdin,0))==MAP_FAILED) /*映射原文件到输入的映射存储区*/ printf(“mmap error); if((dst=mmap(0,statbuf.st_size,PROT_READ|PROT_WRITE,MAP_SHARED,fdout,0)) ==MAP_FAILED) /*映射目标文件到输出的映射存储区*/ printf(“mmap error); memcpy(dst,src,statbuf.st_size);/*复制映射存储区*/ munmap(src,statbuf.st_size); /*解除输入映射*/ munmap(dst,statbuf.st_size); /*解除输出映射*/ close(fdin); close(fdout); } |
9.
名称:: |
mprotect |
功能: |
改变映射存储区的权限 |
头文件: |
#include <sys/mman.h> |
函数原形: |
int mprotect(void *addr,size_t len,int prot); |
参数: |
addr 指向映射存储区的起始地址 len 映射的字节 prot 对映射存储区的保护要求 |
返回值: |
若成功则返回0,若出错则返回-1 |
mprotect可以更改一个现存映射存储区的权限。
10.
名称:: |
msync |
功能: |
同步文件到存储器 |
头文件: |
#include <sys/mman.h> |
函数原形: |
int msync(void *addr,size_t len,int flags); |
参数: |
addr 指向映射存储区的起始地址 len 映射的字节 prot flags |
返回值: |
若成功则返回0,若出错则返回-1 |
如果在共享映射区中的页已被修改,那么我们可以调用msync将该页冲洗到映射的文件中。flags参数使我们对如何冲洗存储区有某种程度的控制。我们可以指定MS_ASYNC标志以简被写页的调度。如果我们希望在返回之前等待写操作的完成,则可指定MS_SYNC标志。一定要制定MSASYNC或MS_SYNC中的一个。MS_INVALIDATE是一个可选的标志,使用它会通知操作系统丢弃与底层存储器没有同步的任何页。