Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1178483
  • 博文数量: 181
  • 博客积分: 4968
  • 博客等级: 上校
  • 技术积分: 1867
  • 用 户 组: 普通用户
  • 注册时间: 2008-01-13 21:52
文章分类

全部博文(181)

文章存档

2015年(2)

2013年(6)

2012年(22)

2011年(41)

2010年(27)

2009年(51)

2008年(32)

我的朋友

分类: LINUX

2010-11-16 11:45:08

利用mmap实现的一个文件拷贝例子

/*
 * gcc -Wall -O3 -o copy_mmap copy_mmap.c
 
*/
#include 
< stdio.h >
#include 
< stdlib.h >
#include 
< string .h >    /*  for memcpy  */
#include 
< strings.h >
#include 
< sys / mman.h >
#include 
< sys / types.h >
#include 
< sys / stat.h >
#include 
< fcntl.h >
#include 
< unistd.h >

#define  PERMS 0600

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

    
if  ( argc  !=   3  )
    {
        fprintf( stderr, 
"  Usage: %s  \n " , argv[ 0 ] );
        exit( EXIT_FAILURE );
    }
    
if  ( ( src  =  open( argv[ 1 ], O_RDONLY ) )  <   0  )
    {
        perror( 
" open source "  );
        exit( EXIT_FAILURE );
    }
    
/*  为了完成复制,必须包含读打开,否则mmap()失败  */
    
if  ( ( dst  =  open( argv[ 2 ], O_RDWR  |  O_CREAT  |  O_TRUNC, PERMS ) )  <   0  )
    {
        perror( 
" open target "  );
        exit( EXIT_FAILURE );
    }
    
if  ( fstat( src,  & statbuf )  <   0  )
    {
        perror( 
" fstat source "  );
        exit( EXIT_FAILURE );
    }
    
/*
     * 参看前面man手册中的说明,mmap()不能用于扩展文件长度。所以这里必须事
     * 先扩大目标文件长度,准备一个空架子等待复制。
     
*/
    
if  ( lseek( dst, statbuf.st_size  -   1 , SEEK_SET )  <   0  )
    {
        perror( 
" lseek target "  );
        exit( EXIT_FAILURE ); 
    } 
    
if  ( write( dst,  & statbuf,  1  )  !=   1  )
    {
        perror( 
" write target "  );
        exit( EXIT_FAILURE );
    } 
    
    
/*  读的时候指定 MAP_PRIVATE 即可  */
    sm 
=  mmap(  0 , ( size_t )statbuf.st_size, PROT_READ,
               MAP_PRIVATE 
|  MAP_NORESERVE, src,  0  );
    
if  ( MAP_FAILED  ==  sm )
    {
        perror( 
" mmap source "  );
        exit( EXIT_FAILURE );
    }
    
/*  这里必须指定 MAP_SHARED 才可能真正改变静态文件  */
    dm 
=  mmap(  0 , ( size_t )statbuf.st_size, PROT_WRITE,
               MAP_SHARED, dst, 
0  );
    
if  ( MAP_FAILED  ==  dm )
    {
        perror( 
" mmap target "  );
        exit( EXIT_FAILURE );
    }
    memcpy( dm, sm, ( size_t )statbuf.st_size );
    
/*
     * 可以不要这行代码
     *
     * msync( dm, ( size_t )statbuf.st_size, MS_SYNC );
     
*/
    
return ( EXIT_SUCCESS );

mmap()好处是处理大文件时速度明显快于标准文件I/O,无论读写,都少了一次用户空间与内核空间之间的复制过程。操作内存还便于设计、优化算法。

文件I/O操作/proc/self/mem不存在页边界对齐的问题,但至少Linux的mmap()的最后一个形参offset并未强制要求页边界对齐,如果提供的值未对齐,系统自动向上舍入到页边界上。malloc()分配得到的地址不见得对齐在页边界上。
       
/proc/self/mem和/dev/kmem不同。root用户打开/dev/kmem就可以在用户空间访问到内核空间的数据,包括偏移0处的数据,系统提供了这样的支持。显然代码段经过/proc/self/mem可写映射后已经可写,无须mprotect()介入。

阅读(3047) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~