Linux系统编程学习之《论使用mmap复制文件》

来源:互联网 发布:mac上安装ipad应用 编辑:程序博客网 时间:2024/05/22 11:35

由于想加速今天使用了mmap来写一个复制文件的程序,发现原来使用mmap来复制文件原来是不够直接用read和write来复制文件快的

也许有人会觉得我不对,不过我首先说明复制背景:

我的复制文件不像《UNIX网络编程卷2》上面说的那样,有一个客户端和一个服务端进程,我的只有一个进程,在这一个进程内进行复制操作。

首先列出一下我写的两个复制文件的函数:

使用mmap复制的函数:

static int copyfile(const char * source, const char * destination, int mode) {int fd_r, fd_w;struct stat file_stat;ssize_t file_len;char *file_buf_r, *file_buf_w;if (0 == mode) {mode = 0660;}fd_r = open(source, O_RDONLY);if (fd_r < 0) {return 1;}if (fstat(fd_r, &file_stat) < 0) {close(fd_r);return 1;}file_len = file_stat.st_size;file_buf_r = (char *) mmap(NULL, file_len, PROT_READ, MAP_SHARED, fd_r,SEEK_SET);if (file_buf_r == MAP_FAILED) {close(fd_r);return 1;}close(fd_r);fd_w = open(destination, O_CREAT | O_RDWR, mode);if (fd_w < 0) {close(fd_r);munmap(file_buf_r, file_len);return 1;}if (ftruncate(fd_w, file_len) < 0) {close(fd_w);munmap(file_buf_r,file_len);unlink(destination);return 1;}file_buf_w = (char *) mmap(NULL, file_len, PROT_WRITE, MAP_SHARED, fd_w,SEEK_SET);if (file_buf_w == MAP_FAILED) {close(fd_w);munmap(file_buf_r, file_len);unlink(destination);return 1;}close(fd_w);if (NULL == memcpy(file_buf_w, file_buf_r, file_len)) {munmap(file_buf_r, file_len);munmap(file_buf_w, file_len);unlink(destination);return 1;}if (msync(file_buf_w, file_len, MS_SYNC) < 0) {munmap(file_buf_r, file_len);munmap(file_buf_w, file_len);unlink(destination);return 1;}munmap(file_buf_r, file_len);munmap(file_buf_w, file_len);return 0;}

接着贴上我使用read和write复制文件的函数代码:

static int copyfile(const char * source,const char * destination,int mode){int srcfd,desfd;int exit_status;off_t filelen;ssize_t nwrite,n;exit_status = 0;srcfd = -1;desfd = -1;char * buf[BUFFSIZE];if (NULL == source || NULL == destination) {exit_status = 1;goto exit_program;}if (0 == mode) {mode = 0660;}if (access(source,F_OK) < 0) {exit_status = 1;goto exit_program;}if ( (srcfd = open(source,O_RDONLY)) < 0 ) {exit_status = 1;goto exit_program;}if (creat(destination,mode) < 0) {exit_status = 1;goto exit_program;}if ((desfd = open(destination,O_WRONLY,O_APPEND)) < 0) {exit_status = 1;goto exit_program;}filelen = lseek(srcfd,0,SEEK_END);lseek(desfd,0,SEEK_SET);nwrite = 0;while (nwrite < filelen) {n = pread(srcfd,buf,BUFFSIZE,nwrite);if (n < 0) {exit_status = 1;goto exit_program;}n = write(desfd,buf,n);if (n < 0) {exit_status = 1;goto exit_program;}nwrite += n;}exit_status = 0;exit_program:if (srcfd >= 0) {close(srcfd);}if (desfd >= 0) {if (1 == exit_status) {unlink(destination);}close(desfd);}return exit_status;}

看这两个函数的代码数量相差不大,但是性能却有所差异

原本我以为使用mmap会使得复制更快,但是结果却是read和write组合复制文件更快些

经过我多次测试,测试复制100个图片文件

使用mmap的函数使用大概2.5s

而使用read和write的函数使用大概2.3s

虽然只有0.2s的差距,但是如果文件数量一大,那么这个差距就显示出来了

我这里并不是说mmap没有用处,本来mmap的定位都是用于进程间共享内存的

所以如果对于复制文件这样没有共享内存的操作,mmap失去了优势,反而可能成为劣势,不如read和write

但是如果是两个进程间通信,如果用read和write对管道(FIFO等)进行数据读写,那么效率肯定是不如直接使用mmap高效

原创粉丝点击