您的位置:首页 > 运维架构 > Linux

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则需要通过系统调用把内核空间的缓存复制到用户空间,再将用户空间缓存复制到内核空间,拷贝次数明显多了一个呢?速度为什么于理论预测的不一致呢?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: