日期:2014-05-16  浏览次数:20715 次

linux存储映射mmap()实现文件复制
学习APUE,书里有个例程是利用linux存储映射I/O复制一个文件(类似于cp命令)

#include "apue.h"
#include <fcntl.h>
#include <sys/mman.h>

int main(int argc,char *argv[])
{
   int fdin,fdout;
   void *src,*dst;
   struct stat statbuf;

   if(argc != 3)
    err_quit("usage: %s <fromfile> <tofile>",argv[0]);

   if((fdin = open(argv[1],O_RDONLY)) <0)
    err_sys("can't open %s",argv[1]);

   if((fdout = open(argv[2],O_RDWR | O_CREAT | O_TRUNC,FILE_MODE)) < 0)
    err_sys("can't creat %s for writing",argv[2]);

   if(fstat(fdin,&statbuf) < 0)
    err_sys("write error");

   /*set size of output file*/
   if(lseek(fdout,statbuf.st_size-1,SEEK_SET) == -1)
    err_sys("lseek error");
   if(write(fdout," ",1) != 1)
    err_sys("write error");

   if((src = mmap(0,statbuf.st_size,PROT_READ,MAP_SHARED,fdin,0)) == MAP_FAILED)
    err_sys("mmap error for input");

   if((dst = mmap(0,statbuf.st_size,PROT_READ | PROT_WRITE,MAP_SHARED,fdout,0)) ==MAP_FAILED)
    err_sys("mmap error for output");

   memcpy(dst,src,statbuf.st_size);
   return 0;
}

我不理解的是/*set size of output file*/下面两个语句,他说这两句程序的目的是写一个字节以设置输出文件的长度,这是什么意思,输入文件的长度不是statbuf.st_size吗?那复制的输出文件长度也是statbuf.st_size啊,利用这个长度分别mmap两个存储区src和dst,然后再memcpy,长度都是statbuf.st_size啊
  干嘛先设置文件偏移量,再写入一个字节,这是为什么啊?难道文件长度是statbuf.st_size-1吗?如果是statbuf.st_size-1,那直接就按statbuf.st_size-1映射、再复制不就行了?这是为什么啊?

 求指点
说话比较啰嗦,麻烦各位耐心点,万分感激

------解决方案--------------------
if(lseek(fdout,statbuf.st_size-1,SEEK_SET) == -1)
       err_sys("lseek error");
if(write(fdout," ",1) != 1)
       err_sys("write error");

这两句相当于 ftruncate(fdout, statbuf.st_size),目的是为了给fdout分配文件块,这样mmap在 shared 模式下才能正确同步内容,否则的话,mmap 映射的内存区比文件大的话,写的数据是可能丢失的。
------解决方案--------------------
lseek是偏移,write是写。

两个动作加起来相当于pwrite。
------解决方案--------------------
不知道直接使用 ftruncate 行不行。