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

由于想加速今天使用了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高效

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值