apue文件中的空洞是如何通过来的?

摘要:空洞的概念 linux 上普通文件的大小与占用空间是两个概念,前者表示文件中数据的长度,后者表示数据占用的磁盘空间,通常后者大于前者,因为需要一些额外的空间用来记录文件的某些统计信息或附加信息、以及切分为块的数据信息 (通常不会占用太多)。
空洞的概念 linux 上普通文件的大小与占用空间是两个概念,前者表示文件中数据的长度,后者表示数据占用的磁盘空间,通常后者大于前者,因为需要一些额外的空间用来记录文件的某些统计信息或附加信息、以及切分为块的数据信息 (通常不会占用太多)。文件占用空间也可以小于文件尺寸,此时文件内部就存在空洞了。 所谓空洞其实就是没有分配存储空间的数据块,当访问这些数据块时,系统返回 0,就如同读到空文件一般,当写这些块时,系统再实地分配对应的存储空间。其实这个和内存中的虚址地址与物理地址的概念非常相似——操作系统可以预分配一大块内存地址,这个地址只是一段连续的数字,用来保证虚拟地址不会被其它人占用,而对应的物理地址只在用到时才分配,这样就避免了一下分配一大块内存带来的浪费问题。同理,如果抽象出一个文件地址和存储地址来的话,完全可以套用上面的结论:连续的文件地址保证用户可以访问任意偏移的文件数据;文件中的空洞又避免了一下子分配太多的物理存储带来的浪费。 所以空洞不光针对文件,也可以针对内存,可以将虚址中的缺页中断理解为填补内存空洞的过程,文件中也有类似的机制。不过也有一些差异,例如内存因进程间共享而引入的 copy-on-write 机制,文件中就没有。文件同一地址的数据如果被多个进程同时写入时,只有最后一个写入的会生效,前面的那些都会被覆盖,因为文件是系统级别的概念,不像内存一样专属于某个进程。 空洞的产生 下面分平台说明。 Linux 所有的类 Unix 系统都差不多,方法比较简单,满足以下两点即可: 设置文件的偏移量 (lseek) 超过文件尾端 并写了某些数据后 (write) 此时原文件末尾到新文件末尾之间将标记为空洞。甚至都不需要写一个程序,就可以验证: $ echo "this is a test" > test.txt $ ls -lh test.txt -rw-rw-r-- 1 yunh yunh 15 Oct 30 16:14 test.txt $ stat test.txt File: test.txt Size: 15 Blocks: 8 IO Block: 4096 regular file Device: 805h/2053d Inode: 35259462 Links: 1 Access: (0664/-rw-rw-r--) Uid: ( 1000/ yunh) Gid: ( 1000/ yunh) Access: 2021-10-30 16:15:00.767760242 +0800 Modify: 2021-10-30 16:14:58.160147599 +0800 Change: 2021-10-30 16:14:58.160147599 +0800 Birth: - $ du -sh test.txt 4.0K test.txt $ truncate -s 1M test.txt $ ls -lh test.txt -rw-rw-r-- 1 yunh yunh 1.0M Oct 30 16:16 test.txt $ stat test.txt File: test.txt Size: 1048576 Blocks: 8 IO Block: 4096 regular file Device: 805h/2053d Inode: 35259462 Links: 1 Access: (0664/-rw-rw-r--) Uid: ( 1000/ yunh) Gid: ( 1000/ yunh) Access: 2021-10-30 16:15:00.767760242 +0800 Modify: 2021-10-30 16:16:02.914508936 +0800 Change: 2021-10-30 16:16:02.914508936 +0800 Birth: - $ du -sh test.txt 4.0K test.txt 上面的例子中,标称 1MB 的 test.txt 文件只占用 4KB 空间。
阅读全文