Linux下的几种文件拷贝方式效率对比
2016-12-07 10:29
344 查看
不管是哪种操作系统,要实现文件拷贝,必须陷入内核,从磁盘读取文件内容,然后存储到另一个文件。实现文件拷贝最通常的做法是:读取文件用系统调用read()函数,读取到一定长度的连续的用户层缓冲区,然后使用write()函数将缓冲区内容写入文件。也可以用标准库函数fread()和fwrite(),但这两个函数最终还是通过系统调用read()和write()实现拷贝的,因此可以归为一类(不过效率肯定没有直接进行系统调用的高)。一个更高级的做法是使用虚拟存储映射技术进行,这种方法将源文件以共享方式映射到虚拟存储器中,目的文件也以共享方式映射到虚拟地址空间中,然后使用memcpy高效地将源文件内容复制到目的文件中。
点击(此处)折叠或打开
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/times.h>
#define error(fmt,args...)
\
printf(fmt, ##args)
; \
printf(":%s\n",strerror(errno))
inline int cp_rw(int srcfd,int dstfd,char
*buf,int
len);
inline int cp_map(int srcfd,int dstfd,size_t
len);
int main(int argc,char
**argv)
{
char buf[8192];
int srcfd,dstfd;
clock_t start,end;
struct tms stm,ntm;
struct stat filestat;
int tck;
char cmdline[30];
if(argc!=3)
printf("usage: cmd ");
tck=sysconf(_SC_CLK_TCK);
start = times(&stm);
if((srcfd=open(argv[1],O_RDONLY))==-1)
{
error("open %s error",argv[1]);
exit(0);
}
if((dstfd=open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0666))==-1)
{
error("creat %s error",argv[2]);
exit(0);
}
fstat(srcfd,&filestat);
if(lseek(dstfd,filestat.st_size,SEEK_SET)==-1)
{
error("lseek error");
exit(0);
}
if(write(dstfd," ",1)!=1)
{
error("write error");
exit(0);
}
cp_map(srcfd,dstfd,filestat.st_size);
close(srcfd);
close(dstfd);
end = times(&ntm);
printf("copying %s to %s using cp_map:filesize=%lu MBytes Using %f seconds\n"
,argv[1],argv[2],filestat.st_size>>20,(end-start)/(double)tck);
sprintf(cmdline,"rm -f %s",argv[2]);
system(cmdline);
start = times(&stm);
if((srcfd=open(argv[1],O_RDONLY))==-1)
{
error("open %s error",argv[1]);
}
if((dstfd=open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0666))==-1)
{
error("creat %s error",argv[2]);
}
cp_rw(srcfd,dstfd,buf,sizeof(buf));
fstat(srcfd,&filestat);
close(srcfd);
close(dstfd);
end = times(&ntm);
printf("copying %s to %s using cp_rw:filesize=%lu MBytes Using %f seconds\n"
,argv[1],argv[2],filestat.st_size>>20,(end-start)/(double)tck);
return 0;
}
inline int cp_rw(int srcfd,int dstfd,char
*buf,int
len)
{
int nread;
while((nread=read(srcfd,buf,len))>0)
{
if(write(dstfd,buf,nread)!=nread)
{
error("write error");
return -1;
}
}
if(nread
==-1)
{
error("read error");
return -1;
}
return 0;
}
inline int cp_map(int srcfd,int dstfd,size_t
len)
{
char *src,*dst;
if((src=mmap(0,len,PROT_READ,MAP_SHARED,srcfd,0))==MAP_FAILED)
{
error("mmap src error");
return -1;
}
if((dst=mmap(0,len,PROT_WRITE,MAP_SHARED,dstfd,0))==MAP_FAILED)
{
error("mmap dst error");
return -1;
}
if(memcpy(dst,src,len)==NULL)
{
error("memcpy error");
return -1;
}
munmap(src,len);
munmap(dst,len);
return 0;
}
运行,拷贝一个1.1G的文件,得到如下结果
[root@garden copy]# ./copy /home/ker.tgz ./ker.tgz
copying /home/ker.tgz to ./ker.tgz using cp_map:filesize=1030 MBytes Using 61.900000 seconds
copying /home/ker.tgz to ./ker.tgz using cp_rw:filesize=1030 MBytes Using 34.330000 seconds
使用read/write的方法居然比mmap的快一倍,这是怎么回事呢?理论上mmap系统调用只进行了一次,而且拷贝文件是直接在内核空间进行的,read/write则需要通过系统调用把内核空间的缓存复制到用户空间,再将用户空间缓存复制到内核空间,拷贝次数明显多了一个呢?速度为什么于理论预测的不一致呢?
点击(此处)折叠或打开
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/times.h>
#define error(fmt,args...)
\
printf(fmt, ##args)
; \
printf(":%s\n",strerror(errno))
inline int cp_rw(int srcfd,int dstfd,char
*buf,int
len);
inline int cp_map(int srcfd,int dstfd,size_t
len);
int main(int argc,char
**argv)
{
char buf[8192];
int srcfd,dstfd;
clock_t start,end;
struct tms stm,ntm;
struct stat filestat;
int tck;
char cmdline[30];
if(argc!=3)
printf("usage: cmd ");
tck=sysconf(_SC_CLK_TCK);
start = times(&stm);
if((srcfd=open(argv[1],O_RDONLY))==-1)
{
error("open %s error",argv[1]);
exit(0);
}
if((dstfd=open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0666))==-1)
{
error("creat %s error",argv[2]);
exit(0);
}
fstat(srcfd,&filestat);
if(lseek(dstfd,filestat.st_size,SEEK_SET)==-1)
{
error("lseek error");
exit(0);
}
if(write(dstfd," ",1)!=1)
{
error("write error");
exit(0);
}
cp_map(srcfd,dstfd,filestat.st_size);
close(srcfd);
close(dstfd);
end = times(&ntm);
printf("copying %s to %s using cp_map:filesize=%lu MBytes Using %f seconds\n"
,argv[1],argv[2],filestat.st_size>>20,(end-start)/(double)tck);
sprintf(cmdline,"rm -f %s",argv[2]);
system(cmdline);
start = times(&stm);
if((srcfd=open(argv[1],O_RDONLY))==-1)
{
error("open %s error",argv[1]);
}
if((dstfd=open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0666))==-1)
{
error("creat %s error",argv[2]);
}
cp_rw(srcfd,dstfd,buf,sizeof(buf));
fstat(srcfd,&filestat);
close(srcfd);
close(dstfd);
end = times(&ntm);
printf("copying %s to %s using cp_rw:filesize=%lu MBytes Using %f seconds\n"
,argv[1],argv[2],filestat.st_size>>20,(end-start)/(double)tck);
return 0;
}
inline int cp_rw(int srcfd,int dstfd,char
*buf,int
len)
{
int nread;
while((nread=read(srcfd,buf,len))>0)
{
if(write(dstfd,buf,nread)!=nread)
{
error("write error");
return -1;
}
}
if(nread
==-1)
{
error("read error");
return -1;
}
return 0;
}
inline int cp_map(int srcfd,int dstfd,size_t
len)
{
char *src,*dst;
if((src=mmap(0,len,PROT_READ,MAP_SHARED,srcfd,0))==MAP_FAILED)
{
error("mmap src error");
return -1;
}
if((dst=mmap(0,len,PROT_WRITE,MAP_SHARED,dstfd,0))==MAP_FAILED)
{
error("mmap dst error");
return -1;
}
if(memcpy(dst,src,len)==NULL)
{
error("memcpy error");
return -1;
}
munmap(src,len);
munmap(dst,len);
return 0;
}
运行,拷贝一个1.1G的文件,得到如下结果
[root@garden copy]# ./copy /home/ker.tgz ./ker.tgz
copying /home/ker.tgz to ./ker.tgz using cp_map:filesize=1030 MBytes Using 61.900000 seconds
copying /home/ker.tgz to ./ker.tgz using cp_rw:filesize=1030 MBytes Using 34.330000 seconds
使用read/write的方法居然比mmap的快一倍,这是怎么回事呢?理论上mmap系统调用只进行了一次,而且拷贝文件是直接在内核空间进行的,read/write则需要通过系统调用把内核空间的缓存复制到用户空间,再将用户空间缓存复制到内核空间,拷贝次数明显多了一个呢?速度为什么于理论预测的不一致呢?
相关文章推荐
- 5、 java 编写程序拷贝一个文件, 尽量使用效率高的方式.
- Linux创建新文件的几种方式
- 【转】关于几种访问GameObject方式的效率对比
- java中多种写文件方式的效率对比实验
- JAVA中几种文件操作流的效率对比
- Linux 下查找文件的几种方式
- GoLang 文件写入方式效率对比
- Linux c==几种进程间通信方式的特点对比 (22)
- 主机与设备之间文件拷贝的几种方式
- java中多种写文件方式的效率对比实验
- linux查看文件的几种方式
- Neo4J几种数据导入方式的效率对比
- [笔记]Go语言写文件几种方式性能对比
- linux中几种查找文件方式的比较
- linux 新建文件 和清空文件几种方式
- linux几种不同格式文件的安装方式
- Java:io流写入文件的四种实现方式的效率对比
- 几种读大文件方法的效率对比测试
- Linux主机之间传输文件的几种方法对比
- Linux c==几种进程间通信方式的特点对比