通常我们读写文件时,都是用系统提供的write和read函数,但是我们都知道文件IO函数操作文件流效率要低于mmap,因为mmap相对write/read省去将数据拷贝到用户态的操作。那么他们之间的差距有多大呢,我们来用事实说话。
1.如何快速创建一个大文件
我们做这个测试之前,需要准备一个足够大的文件来进行对比,那么在linux下,系统为我们准备了现成的方法去创建一个大文件。主要有三种方法:
-
1.truncate
$ truncate -s 20M filename
在命令行输入该命令就可以创建出一个20MB的文件,但是后面才发现,该文件的大小是假的,具体为什么,大家可以去研究一下,这里不做赘述。 -
2.fallocate
$ fallocate -l 20M filename
在命令行输入以下命令也可以创建出一个指定大小的文件,并且该大小是真实的,我们测试就是选用的这种方法。 -
3.dd
$ dd if=/dev/zero of=filename count=10 bs=20M
这个也是真是的大小,但是比较复杂,所以没用这个,至于这个和上面两个有什么区别,感兴趣可以自行研究一下。
2.用mmap拷贝文件
先贴上用mmap拷贝文件的方法,如果对mmap不熟悉的可以参考我上一篇总结的文章mmap ---- 内存映射原理。直接上代码:
1 #include<stdio.h>
2 #include<sys/mman.h>
3 #include<unistd.h>
4 #include<sys/types.h>
5 #include<stdlib.h>
6 #include<fcntl.h>
7 #include<sys/stat.h>
8 #include<string.h>
9
10 void mmapcopy(int sfd, size_t slen, int dfd) {
11 void *sptr = mmap(NULL, slen, PROT_READ, MAP_SHARED, sfd, 0);
12 void *dptr = mmap(NULL, slen, PROT_READ | PROT_WRITE, MAP_SHARED, dfd, 0);
13 if(dptr == MAP_FAILED) {
14 printf("mmap failed.");
15 return;
16 }
17
18 memcpy(dptr, sptr, slen);
19
20 munmap(sptr, slen);
21 munmap(dptr, slen);
22 }
23
24 int main(int argc, char* argv[]) {
25 if(argc != 3) {
26 printf("Usage: %s <src filename> <des filename>", argv[0]);
27 return -1;
28 }
29
30 int sfd;
31 int dfd;
32
33 if((sfd = open(argv[1], O_RDONLY)) < 0) {
34 printf("open src file failed.");
35 return sfd;
36 }
37
38 if((dfd = open(argv[2], O_CREAT | O_RDWR, 0664)) < 0) {
39 printf("create dst file failed.");
40 return dfd;
41 }
42
43 struct stat fst;
44 fstat(sfd, &fst);
45 truncate(argv[2], fst.st_size);
46 mmapcopy(sfd, fst.st_size, dfd);
47
48 close(sfd);
49 close(dfd);
50
51 return 0;
52 }
3.用普通文件IO拷贝文件
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<sys/types.h>
4 #include<stdlib.h>
5 #include<fcntl.h>
6
7 int main(int argc, char* argv[]) {
8 if(argc != 3) {
9 printf("Usage: %s <src filename> <des filename>", argv[0]);
10 return -1;
11 }
12
13 int sfd;
14 int dfd;
15
16 if((sfd = open(argv[1], O_RDONLY)) < 0) {
17 printf("open src file failed.");
18 return sfd;
19 }
20
21 if((dfd = open(argv[2], O_CREAT | O_RDWR, 0664)) < 0) {
22 printf("create dst file failed.");
23 return dfd;
24 }
25
26 char buf[1024];
27 int ret;
28 while(1) {
29 ret = read(sfd, buf, 1024);
30 if(ret < 0) {
31 printf("read error.");
32 break;
33 }
34 else if(ret == 0) {
35 printf("read end.");
36 break;
37 }
38
39 if(ret != write(dfd, buf, ret)) {
40 printf("write error.");
41 break;
42 }
43
44 }
45
46 close(sfd);
47 close(dfd);
48
49 return 0;
50 }
4.对比测试
分别测试了500M,1G和2G的文件拷贝,更大的没试,按照上面的规律来看,mmap似乎都是会快一点的,理论和实际都已经证明了,mmap进行文件拷贝的时候,是比较快的,因为它毕竟省去了copy_to_usr这一次拷贝。