UNIX环境高级编程APUE练习4.6-实现类似cp(1)的程序,保留文件中的空洞

1 题面

编写类似cp(1)的程序,它复制包含空洞的文件,但是不将字节0写到输出文件中去。

2 基本思路

  • 首先要搞清楚空洞的性质以判断一个文件是否有空洞,以及空洞的位置
  • 知道了空洞的位置之后,读到源文件中的空洞部分时,在目标文件中lseek相应的长度

3 创建空洞文件,同时探索空洞性质

交替lseekwrite,逐渐增大间隔长度。比较文件的大小和实际占用的block数目

  • 测试源码
点击展开代码
  • MAC OSX 10.1.4.6测试结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
^_^$ ll -s
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize1
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize1024
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize128
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize16
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize16384
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize2
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize2048
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize256
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize32
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize32768
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize4
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize4096
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize512
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize64
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize8
128 -rw-r--r-- 1 chenzf staff 65536 12 28 20:08 holesize8192

Mac OSX上创建不了空洞文件,因为默认的文件系统是HFS +,不支持稀疏文件

  • Ubuntu18 4.15.0-60-generic测试结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
^_^$ ll -s
64 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize1
64 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize1024
64 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize128
64 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize16
32 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize16384
64 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize2
64 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize2048
64 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize256
64 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize32
32 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize32768
64 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize4
32 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize4096
64 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize512
64 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize64
64 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize8
32 -rw-r--r-- 1 chen chen 65536 12月 25 00:08 holesize8192

4KB以上才实际创建空洞。
因为在linux的文件系统中,磁盘分配的最小物理单元为簇。(即使文件大小不足以占用满一簇,该簇空余的磁盘存储仍旧是该文件的)

所以可以根据这个性质,判断文件是否是空洞文件。有空洞的文件,用文件大小计算的block数至少比实际占用的block数大1个簇的block数

如何可移植地获取簇的大小

1
pagesize = sysconf(_SC_PAGESIZE);

初步实现功能

  • 源码
点击展开代码
  • 测试结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
^_^$ ./my_cp holesize2048 holesize2048.cp
pagesize: 4096
st.st_blocks: 128
st.st_blksize: 4096
st.st_size: 65536
holesize2048 is not a sparse-block file!
chen@ubuntu18:~/study/apue.3e/exercises/4
^_^$ ./my_cp holesize4096 holesize4096.cp
pagesize: 4096
st.st_blocks: 72
st.st_blksize: 4096
st.st_size: 65536
holesize4096 is a sparse-block file!

^_^$ ll -s
total 1708
64 -rw-r--r-- 1 chen chen 65536 1月 6 17:27 holesize2048
64 -rw-r--r-- 1 chen chen 65536 1月 6 17:27 holesize2048.cp
36 -rw-r--r-- 1 chen chen 65536 1月 6 17:27 holesize4096
32 -rw-r--r-- 1 chen chen 65536 1月 6 17:27 holesize4096.cp

空洞文件可以正常拷贝

尝试优化程序

上面的程序仅在判断文件是否含有空洞时利用的空洞的最小限制。而在实际读写时并没有利用该性质。

这样较短的0字节也会当成是空洞,导致系统调用次数的增加,性能的降低

要优化性能,必须进一步探究空洞的性质。在什么样的情况下才创建空洞(不实际占用磁盘空间的块)?

  • 测试程序源码

此程序创建了3个文件:

- 文件1先`write`了1K的非零数据,然后`lseek` 7K-1字节。循环2次。
- 文件2先`write`了1K的非零数据,然后`lseek` 7K字节。循环2次
- 文件3先`write`了1K的非零数据,然后`lseek` 7K+1字节。循环2次
点击展开代码
  • 测试结果
1
2
3
4
^_^$ ll -s
12 -rw-r--r-- 1 chen chen 9215 1月 6 15:07 holesize4096-1
8 -rw-r--r-- 1 chen chen 9216 1月 6 15:07 holesize4096-2
8 -rw-r--r-- 1 chen chen 9217 1月 6 15:07 holesize4096-3

可见空洞必须从一页的起始位置开始计算,并且等于或超过pagesize,才不占用实际磁盘空间

优化后程序

  • 源码
点击展开代码
  • 对比测试

构造一个文件,除了开头一个空洞,其余数据为0x00,0x01的100000次重复

用优化前的程序拷贝该文件10000次,大约2000s

用优化后的程序拷贝该文件10000次,大约30s

-------------本文结束感谢您的阅读-------------

欢迎关注我的其它发布渠道

Powered By Valine
v1.5.2