使用mmap()和使用 read()write()实现文件拷贝的对比

最近上课老师说了这样一句话:mmap()内存映射可以实现文件的拷贝,并且速度明显快于一般的文件拷贝,于是
我试着实现了两种文件拷贝所花费时 间的比较,首先看代码:

#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 1


void 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);

    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){
        perror( "mmap target" );
        exit( EXIT_FAILURE );
    }
   
    memcpy(end,start,(size_t)sb.st_size);
    munmap(start,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;
    int time_start,time_end;
    gettimeofday(&tv,&tz);
    time_start = (int)tv.tv_usec;
    my_copy1();
    printf("/ndone./n/n");
    gettimeofday(&tv,&tz);
    time_end = (int)tv.tv_usec;
    printf("using /"mmap()/" to copy costs %d microseconds /n",time_end-time_start);
   
    gettimeofday(&tv,&tz);
    time_start = (int)tv.tv_usec;
    my_copy2();
    gettimeofday(&tv,&tz);
    time_end = (int)tv.tv_usec;
    printf("using /"read() and write()/" to copy costs %d microseconds /n",time_end-time_start);
}


代码不是很难,中 间使用了一些LinuxC的一些函数,不懂的可以自己查阅相关资料。我现在主要使想就两种
不同的拷贝的实现在所花费的时间上的一些比较以及的出我 自己的一些观点,调试程序时可以将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 次的磁盘操作,因此在这上面浪费了大量的时间。所以了

好的,就这么多了,如果有什么问题可以直接留言, 互相讨论,谢谢

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在Linux下,mmap函数可以用来将文件或设备的一部分物理内存映射到进程的虚拟地址空间中,从而实现进程和文件或设备的直接交互。使用mmap函数可以提高文件或设备的读写效率,避免了频繁的系统调用和缓冲区的拷贝mmap函数的原型为: ```c void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); ``` 各个参数的含义如下: - addr:映射区域的首地址,一般设为NULL,由系统自动分配。 - length:映射区域的长度,单位是字节。 - prot:映射区域的保护模式,可以是PROT_READ、PROT_WRITE或PROT_EXEC的组合。 - flags:映射区域的标志,可以是MAP_SHARED、MAP_PRIVATE、MAP_FIXED等的组合。 - fd:需要映射的文件描述符。 - offset:文件偏移量,表示从文件的哪个位置开始映射。 mmap函数返回映射区域的首地址或者MAP_FAILED,表示映射失败。 使用mmap函数时,需要先打开文件或设备,并获取相应的文件描述符。然后,调用mmap函数将文件或设备的一部分物理内存映射到进程的虚拟地址空间中。最后,使用指针来访问映射区域的数据,进行读写操作。使用完映射区域后,需要调用munmap函数解除映射关系。 需要注意的是,使用mmap函数进行读写操作时,需要考虑到内存对齐和边界问题,否则可能会出现读写错误。同时,对于设备文件的映射,还需要考虑到设备驱动程序的特殊要求,比如缓冲区的大小和对齐方式等。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值