【Chapter4*编程总结一*】(含源码)复制空洞文件且不把0复制到新文件

一、写在前面

不积跬步无以至千里,一点点累积最后达到意想不到的效果。认真对待每一个小细节,一点点改正修订,往往是问题关键所在。

二、coding中遇到的坑

步骤一:创建两个文件,一个是空洞文件,另一个是非空洞文件,分析比较两者不同。

2-1 shell中出现乱码

创建无空洞文件时,shell中出现乱码。观察到新创建的文件大小为0,没有数据写入。初步推测文件描述符的问题。在这里插入图片描述
查看创建文件代码:

if(fd2=creat(strcat(argv[1],"_copy"),0777)==-1){                     
 	 err_sys("创建无空洞文件失败!");     }

OMG!竟然少加了一个括号,也就是把(fd2=creat())作为一个整体,这样判断是fd2与-1的关系。OK,就这样解决了~ 等等,如果对于每个问题,就这么简单放过,那就没有任何总结了呀~一定要搞懂它,这些不起眼的小错误是很重要的!

“错误”的情况下,原式为,同理是fd2=1==-1,按照C运算符优先级,==的优先级高于=,则fd2的值:0,这在linux中对应的是标准输入,所以在shell框中出现了我们即将写在fd2中的数据,且fd2文件大小为0.

fd2=creat(strcat(argv[1],"_copy"),0777)==-1

2-2 有空洞和无空洞文件占磁盘块大小一样

本来是用磁盘快大小来区分有空洞文件和无空洞文件的,这下竟然是一样的,上图:c是有空洞,c_copy是无空洞

  4 -rwxrwxr-x 1 fairy fairy    1030 11月  8 15:54 c
  4 -rwxrwxr-x 1 fairy fairy    1030 11月  8 15:54 c_copy

这两个文件竟然一致,占用数据块大小都是4,看字节数是1030个字节,神奇了~按照系统默认的1024字节块,应该是1030/1024,刚好超过1个,不足两个。怎么变成4个了呢?

原因:在linux的文件系统中,磁盘的最小物理单元为簇,每次创建一个文件则为该文件系统分配一个簇或这簇的倍数(即使文件大小不足以占用满一簇,该簇空余的磁盘存储仍旧是该文件的),系统为文件分配的簇为4KB。

ls报告块数单位是1024个字节,(通过df命令查看,第一行文件系统后面1k-blocks)则显示为4。同理,观察到所有分配块数都是4的整数倍。

有的报告块数单位也是512,这依据于POSIX标准,GNU和POSIX的兼容性可查看博客:https://www.ibm.com/developerworks/cn/linux/l-cn-posix/index.html

fairy@ubuntu:~/Unix_Code/Chapter4$ df
Filesystem     1K-blocks     Used Available Use% Mounted on
udev             1509900        0   1509900   0% /dev
tmpfs             306204     8948    297256   3% /run
/dev/sda1       19478204 13193368   5272356  72% /
tmpfs            1531008      252   1530756   1% /dev/shm
tmpfs               5120        4      5116   1% /run/lock
tmpfs            1531008        0   1531008   0% /sys/fs/cgroup
tmpfs             306204       64    306140   1% /run/user/1000

2-3 segmentation fault (core dumped)

这个问题虽说是老生常谈,然而还是一直出错,遇到一次总结一次。参考博客:https://www.cnblogs.com/zl-graduate/p/5735288.html

我这次是内存上出笑话了,由于申请的数组是在栈上的,栈的最大空间是8M,使用ulimit命令可查看,那申请数组越界就会出现段错误。

fairy@ubuntu:~/Unix_Code/Chapter4$ ulimit -s
8192
fairy@ubuntu:~/Unix_Code/Chapter4$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 11795
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 11795
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

三、总结

3-1 空洞文件的大小

在创建了一个有空洞和一个无空洞文件后,使用ls -ls观察大小。两个字节数都是7340038,然而有空洞文件只占用了8个1024个字节,而无空洞文件占用了7172个1024个字节,可以看出占用磁盘数差距较大。

 8 -rwxrwxr-x 1 fairy fairy 7340038 11月  8 11:12 b
7172 -rwxrwxr-x 1 fairy fairy 7340038 11月  8 11:12 b_copy

计算7172*1024=7344128>7340038,报告显示的字节数要大于实际磁盘块上的字节数,有可能是文件系统使用了若干块存放指向实际数据块的指针,对磁盘占用进行了优化。

3-2 复制有空洞文件思路

对于有空洞文件复制,cat是把空洞部分直接填充为0,去掉文件空洞。cp是保留空洞,也创建一个同样的空洞文件。这两个最终生成文件大小不一致。

重要的,如何判断该文件中含有空洞?文件大小/文件块大小>文件块数?
可使用stat结构中的3个参数。

st_size 常规文件长度,单位字节
st_blksize 最佳IO块大小
st_blocks 分配磁盘块数

比如查看上一步创建的空洞文件,获得

fairy@ubuntu:~/Unix_Code/Chapter4$ ./4-6 b b4
st_size:7340038
st_blocks:16
st_blksize:4096

复制有空洞文件,但不把空洞复制到新文件中,只保留有数据的内容,参考cp的源码思路,只是遇到空洞时,跳过即可。参考链接:https://blog.csdn.net/wangxiaoqin00007/article/details/6621209

1、 判断目标文件是否存在,如果存在则清空目标文件,如果不存在则创建目标文件
2、根据目标文件的逻辑块大小,创建拷贝缓冲区
3、判断源文件是否有空洞:文件大小/文件块大小 > 块数 ?
4、读取源文件存放到缓冲区,每次读取一块
5、在第3步中判断,如果存在文件空洞,则对缓冲区数据进行判断,如果缓冲区中的数据均为0,则认为该数据快为空洞,否则认为是正常文件数据
6、如果数据块为空洞,则调用lseek,在目标文件中创建一个空洞;否则拷贝缓冲区数据到目标文件
7、判断本次读取是否读到源文件的文件尾,如果是,则判断本次读取的是否是空洞,如果是空洞则在文件的最后写入""
8、重复1 ~ 7
9、关闭目标文件、源文件

四、源代码

1)创建两个文件,有无空洞:
https://pan.baidu.com/s/1UB8lV3NN2ObIfNVw8d5Tkg
2)复制有空洞文件,不复制空洞
https://pan.baidu.com/s/1ynMuFDw0syCVjVwGcOVlUg

猜你喜欢

转载自blog.csdn.net/vainfanfan/article/details/83863860