利用mmap实现的一个文件拷贝例子,供大家参考,具体内容如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
/*
* 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()介入。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:http://blog.chinaunix.net/uid-20662363-id-1904142.html