mmap拷贝文件

来源:互联网 发布:中国科技大学人工智能 编辑:程序博客网 时间:2024/05/16 06:26
#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <sys/mman.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <sys/time.h>#include <string.h>#define BUFFER_SIZE 1void my_copy1(){    int fin,fout;   //文件描述符    void *start;    void *end;    struct stat sb;    if((fin = open("file.in",O_RDONLY)) < 0){        perror("open error");        exit(EXIT_FAILURE);    }    if((fout = open( "file.out",O_RDWR | O_CREAT | O_TRUNC,00600)) < 0 ){        perror( "write error" );        exit( EXIT_FAILURE );    }       fstat(fin,&sb);    //这块必须给fout一个需求大小的偏移,因为mmap没有扩展空间的能力    if(lseek(fout,sb.st_size-1,SEEK_SET) < 0 ){        exit(EXIT_FAILURE);    }    if(write(fout, &sb,1) != 1 ){        exit(EXIT_FAILURE);    }       start = mmap(NULL,sb.st_size,PROT_READ,MAP_PRIVATE,fin,0);    if(start == MAP_FAILED)        return;          end = mmap(0,(size_t)sb.st_size,PROT_WRITE,MAP_SHARED,fout,0);    if(end == MAP_FAILED){        return ;    }      memcpy(end,start,(size_t)sb.st_size);       munmap(start,sb.st_size); //关闭映射    munmap(end,sb.st_size);       close(fin);    close(fout);    return;}void my_copy2(){    int fin,fout;    int bytes_read,bytes_write;    char buffer[BUFFER_SIZE];    char *ptr;    if((fin = open("file.in",O_RDONLY)) < 0){        perror("open error");        exit(EXIT_FAILURE);    }    if((fout = open( "file.out",O_RDWR | O_CREAT | O_TRUNC,00700)) < 0 ){        perror( "write error" );        exit( EXIT_FAILURE );    }    while(bytes_read=read(fin,buffer,BUFFER_SIZE)){        if((bytes_read==-1)&&(errno!=EINTR))            break;        else if(bytes_read>0){            ptr=buffer;            while(bytes_write=write(fout,ptr,bytes_read)){                if((bytes_write==-1)&&(errno!=EINTR))                    break;                else if(bytes_write==bytes_read)                    break;                else if(bytes_write>0){                    ptr+=bytes_write;                    bytes_read-=bytes_write;                }            }            if(bytes_write==-1)               break;         }    }      close(fin);    close(fout);    return;}main(){    struct timeval tv;    struct timezone tz;    long time_start,time_end;    gettimeofday(&tv,&tz);    time_start = tv.tv_sec*1000000 + tv.tv_usec;    my_copy1();    printf("\ndone.\n\n");    gettimeofday(&tv,&tz);    time_end = tv.tv_sec*1000000 + tv.tv_usec;    printf("using \"mmap()\" to copy costs %ld microseconds \n",time_end - time_start);       gettimeofday(&tv,&tz);    time_start = tv.tv_sec*1000000 + tv.tv_usec;    my_copy2();    gettimeofday(&tv,&tz);    time_end = tv.tv_sec*1000000 + tv.tv_usec;//这块之前有时会出现打印出的负数,后来查看gettimeofday()函数,才知道,我所使用的微秒位在满一秒//的时候会进位到秒,也即是微秒位清零。所以,正确的方法是在计算time_start和time_end的时候加上//秒这一位,不过要首先转换其成为微秒。    printf("using \"read() and write()\" to copy costs %ld microseconds \n",time_end - time_start);}

调试程序时可以将BUFFER_SIZE
随意更改一个数字,表示的是使用read函数从文件中一次读取的字符个数。当然,强调了这个必然有原因。
如果BUFFER_SIZE很小的话,最终的结果差别很大。比如我的
BUFFER_SIZE=1时我的运行结果如下:
zhou@zhou:~/LinuxC/file/mmcopy$ ./mmap

done.

using "mmap()" to copy costs 591 microseconds
using "read() and write()" to copy costs 505337 microseconds
zhou@zhou:~/LinuxC/file/mmcopy$
两个完全不是一个数量级的。下面换个数字
BUFFER_SIZE=10000时我的运行情况如下:
zhou@zhou:~/LinuxC/file/mmcopy$ ./mmap

done.

using "mmap()" to copy costs 594 microseconds
using "read() and write()" to copy costs 585 microseconds
zhou@zhou:~/LinuxC/file/mmcopy$
这时两个的消耗时间很接近,可以想象。如果BUFFER_SIZE定义的很大的话,那么read()write()方法将会
非常快,但是。如果你要拷贝的文件很小呢,加入只有100字节,但是你却每次申请10000个字节,这样岂不
是很浪费内存。这也就是mmap()的优势,不仅没有浪费内存,而且速度相当的快。
话题一转,这是为什么呢,我的理解使这样的:mmap首先将要拷贝的文件的内容全部映射到内存,然后写到目
的文件,总共的磁盘操作就两次,而read()write()不同,会根据你的BUFFER_SIZE定义的,然后会执行
(文件内容的总的字节数/BUFFER_SIZE)*2 次的磁盘操作,因此在这上面浪费了大量的时间。
原创粉丝点击