Linux文件空洞与稀疏文件
From:http://www.topjishu.com/8277.html
From:http://blog.csdn.net/clamercoder/article/details/38361815
Linux_File_Hole_And_Sparse_Files
參考unix環(huán)境高級編程第三版 54頁和90頁!!! ( 文件I/O章節(jié) ?lseek函數(shù) 。文件和目錄章節(jié) 文件長度)
文件空洞
在這種情況下,對該文件的下一次寫將延長該文件,并在文件中構(gòu)成一個空洞。位于文件中但沒有寫過的字節(jié)
都被設(shè)為 0。
在文件里創(chuàng)造“空洞(hole)”。
沒有被實際寫入文件的所有字節(jié)由重復的 0 表示??斩词欠裾加糜脖P空間是由文件系統(tǒng)(file system)決定
的
?
稀疏文件(Sparse File)
空間。
下面是稀疏文件的創(chuàng)建與查看
Linux文件系統(tǒng)inode數(shù)據(jù)塊存儲
索引節(jié)點采用了多重索引結(jié)構(gòu),主要體現(xiàn)在直接指針和3個間接指針。直接指針包含12個直接指
針塊,它們直接指向包含文件數(shù)據(jù)的數(shù)據(jù)塊,緊接在后面的3個間接指針是為了適應文件的大小
變化而設(shè)計。
Linux稀疏文件inode數(shù)據(jù)塊存儲
文件系統(tǒng)存儲稀疏文件時,inode索引節(jié)點中,只給出實際占用磁盤空間的Block 號,
數(shù)據(jù)全零且不占用磁盤空間的文件Block并沒有物理磁盤Block號。
Linux稀疏文件inode數(shù)據(jù)塊存儲
- 文件空洞部分不占用磁盤空間
- 文件所占用的磁盤空間仍然是連續(xù)的
實例:
[root@localhost mnt]# du -sh sparse-file 20K sparse-file [root@localhost mnt]# ls -lh sparse-file -rw-r--r-- 1 root root 1.1G Oct 15 10:36 sparse-file [root@localhost mnt]# debugfs: stat sparse-file Inode: 49153 Type: regular Mode: 0644 Flags: 0x0 Generation: 3068382963 User: 0 Group: 0 Size: 1073742848 File ACL: 0 Directory ACL: 0 Links: 1 Blockcount: 40 Fragment: Address: 0 Number: 0 Size: 0 ctime: 0x507b76af -- Mon Oct 15 10:36:31 2012 atime: 0x507b765f -- Mon Oct 15 10:35:11 2012 mtime: 0x507b76af -- Mon Oct 15 10:36:31 2012 BLOCKS: (IND):106496, (256):106497, (DIND):106504, (IND):106505, (262144):106506 TOTAL: 5Linux文件系統(tǒng)數(shù)據(jù)塊存儲多重索引
- Linux文件系統(tǒng)數(shù)據(jù)存放采用inode多
重索引結(jié)構(gòu),有直接指針和3個間接指
針。
類似于編程中的變量定義:
unsigned long blk;
unsigned long *blk;
unsigned long **blk;
unsigned long ***blk; - 直接指針直接指向保存數(shù)據(jù)的Block
號。 - 一級指針指向一個Block,該Block中
的數(shù)據(jù)是Block指針,指向真正保存數(shù)
據(jù)的Block。
?二級三級指針以此類推。
如Blocks大小為4096,則前12個直接指針就可以保存48KB文件。
假設(shè)每個指針占用4個字節(jié),則一級指針指向的Block可保存4096/4個
指針,可指向1024個Blocks。一級指針可存儲文件數(shù)據(jù)大小為1024*4096 =
4MB。
同樣按照Blocks大小為4096,則二級指針可保存的Block指針數(shù)量為(4096/4) *
(4096/4) = 1024*1024。則二級指針可保存的文件數(shù)量大小為(1024*1024)*4096
= 4GB。
以一級、二級指針計算方法類推,三級指針可存儲的文件數(shù)據(jù)大小為
(1024*1024*1024)*4096 = 4TB。
1.什么是空洞文件?
“在UNIX文件操作中,文件位移量可以大于文件的當前長度,在這種情況下,對該文件的下一次寫將延長該文件,并在文件中構(gòu)成一個空洞,這一點是允許的。位于文件中但沒有寫過的字節(jié)都被設(shè)為 0。” ? ? ?--摘自“百度百科”
從上面的描述可以將空洞文件的特點表述為:offset > 實際文件大小。那這又有什么表現(xiàn)和意義呢?我們下面慢慢分析。
( http://blog.csdn.net/shenlanzifa/article/details/44016537?)
文件空洞
我們知道lseek()系統(tǒng)調(diào)用可以改變文件的偏移量,但如果程序調(diào)用使得文件偏移量跨越了文件結(jié)尾,然后再執(zhí)行I/O操作,將會發(fā)生什么情況? read()調(diào)用將會返回0,表示文件結(jié)尾。令人驚訝的是,write()函數(shù)可以在文件結(jié)尾后的任意位置寫入數(shù)據(jù)。在這種情況下,對該文件的下一次寫將延長該文件,并在文件中構(gòu)成一個空洞,這一點是允許的。從原來的文件結(jié)尾到新寫入數(shù)據(jù)間的這段空間被成為文件空洞。調(diào)用write后文件結(jié)尾的位置已經(jīng)發(fā)生變化。
在Linux系統(tǒng)之中,文件結(jié)束符EOF根本不是一個字符,而是當系統(tǒng)讀取到文件結(jié)尾,所返回的一個信號值(也就是-1),至于系統(tǒng)怎么知道文件的結(jié)尾,資料上說是通過比較文件的長度。
文件空洞占用任何磁盤空間,直到后續(xù)某個時點,在文件空洞中寫入了數(shù)據(jù),文件系統(tǒng)才會為之分配磁盤塊。空洞的存在意味著一個文件名義上的大小可能要比其占用的磁盤存儲總量要大(有時大出許多)。向文件空洞中寫入字節(jié),內(nèi)核需要為其分配存儲單元,即使文件大小不變,系統(tǒng)的可用磁盤空間也將減少。這種情況并不常見,但也需要了解。
下面看一個例子:(轉(zhuǎn)自http://blog.csdn.net/wangxiaoqin00007/article/details/6617801)
ls -l file ? ? ? ?查看文件邏輯大小 ( 即文件的實際大小?)
du -c file???? 查看文件實際占用的存儲塊多少 (即文件實際占用的磁盤空間大小)
od -c file ? ? 查看文件存儲的內(nèi)容 (od命令:http://blog.csdn.net/freeking101/article/details/78182731)
空洞文件就是有空洞的文件,在日常的常識中,我們使用的文件存放在硬盤分區(qū)上的時候,有多大的內(nèi)容就會占用多大的空間,比如這個文本文件里面寫有1000個asc字符,那么就會占用磁盤上1000B的存儲空間,為了便于管理文件,文件系統(tǒng)都是按塊大小來分配給文件的,假如這個文件系統(tǒng)一個塊是4096的話,那么這個文件就會占用一個塊的,無論實際的內(nèi)容是1B還是4000B.如果我們有一個4MB的文件,那么它會在分區(qū)中占用:4MB/4096B=1000個塊.
現(xiàn)在我們先做一個實際的無空洞文件來看看:
#dd if=/dev/urandom of=testfile1 bs=4096 count=1000
這個命令會從/dev/urandom文件復制1000個塊,每塊大小4096,到testfile1文件去.
好了,我們已經(jīng)有了testfile1這么一個4M的文件了,里面填充了一些隨機的內(nèi)容,你可以more一下.
然后用ls -l查看這個文件的大小是4096000,用du -h testfile1來查看的話,文件占用的磁盤大小是4M,兩者是一樣的.
下來是我們的重點,空洞文件,假如我們有一個文件,它有4M的大小,但是它里邊很大一部分都是沒有存放數(shù)據(jù)的,這樣可不可以呢?試一下:
#dd if=/dev/urandom of=testfile2 bs=4096 seek=999 count=1
這個命令跟前一個命令相似,不同的是,它其實復制了1個塊的內(nèi)容,前面的999個塊都跳過了.
我們ls -l一下,發(fā)現(xiàn)文件的大小還是4096000,用du -h testfile2查看,占用的塊大小是4K
我們發(fā)現(xiàn),雖然文件是4M,但是實際在磁盤上只占用了4K的大小,這就是空洞文件的神奇之處.
實際中的空洞文件會在哪里用到呢?常見的場景有兩個:
一是在下載電影的時候,發(fā)現(xiàn)剛開始下載,文件的大小就已經(jīng)到幾百M了.
二是在創(chuàng)建虛擬機的磁盤鏡像的時候,你創(chuàng)建了一個100G的磁盤鏡像,但是其實裝起來系統(tǒng)之后,開始也不過只占用了3,4G的磁盤空間,如果一開始把100G都分配出去的話,無疑是很大的浪費.
然后講一下底層的實現(xiàn)吧,其實這個功能關(guān)鍵得文件系統(tǒng)支持,貌似FAT就不可以吧,linux下一直都很好的支持這一特性,我們舉個最簡單的ext的例子吧,ext中記錄文件實際內(nèi)容的對應信息的東東是一個叫索引表的東西,里面有十幾個條目,每個條目存放對應文件內(nèi)容塊的塊號,這樣就可以順序找到對應的文件內(nèi)容了,大家可能說,幾M的一個文件,十幾個項哪夠啊,不必擔心,一般索引表前面幾個項目是直接指向文件內(nèi)容的,如果這幾個不夠的話,往后的第一個項目不會指向文件內(nèi)容塊,而會指向一個存放項目的塊,這樣一下多出N個項目來,如果這樣還不夠,下面的那個是存放指向指向的項目,不好意思,我也繞暈了,總之,前面的是直接指向,下面這個是二級指向,再下面的是二級指向,以此類推,這樣,文件系統(tǒng)就可以處理T數(shù)量級別的文件,看下圖:
到了空洞文件這里呢,我們只需要把指向沒有文件內(nèi)容部分的索引項目置NULL就好了,這樣就不會指向?qū)嶋H的數(shù)據(jù)塊了,也不會占用磁盤空間了,就這么easy~
至于btrfs這些新一代文件系統(tǒng)呢,在空洞文件這里的原理跟ext還是類似的.
最后介紹一下linux對空洞文件的處理,經(jīng)過我最近的一些測試所得:
在同一文件系統(tǒng)ext4下,cat一個空洞文件到新文件,新文件不再是空洞文件,cp一個空洞文件到新文件,新文件仍然是空洞文件.
在btrfs跟ext4之間做的結(jié)果同上面是一致的,但是在不同文件系統(tǒng)之間cp,因為不同文件系統(tǒng)分配的最小單元不同,所以du結(jié)果會不同.
在nfs的客戶端下,在nfs目錄下去cp,新文件仍然是空洞文件!!!但是cp會逐個的去比較文件的內(nèi)容,所以,受網(wǎng)絡(luò)狀況搞得影響,過程有時候會很慢.
2.怎么獲得一個空洞文件?
在linux下,利用lseek人為的修改offset可以獲得一個空洞文件。
[cpp]?view plain?copy
上面的程序創(chuàng)建了一個空洞文件和一個同樣大小的非空洞文件,接下來我們將以這兩個文件作為基礎(chǔ)進行空洞文件的分析。
3.空洞文件的表現(xiàn)
空洞文件特點就是offset大于實際大小,也就是說一個文件的兩頭有數(shù)據(jù)而中間為空,以‘\0‘填充。那文件系統(tǒng)會不會不做任何處理的將其存放在硬盤上呢?答案是否定的,文件系統(tǒng)沒有傻到這種程度,因為這實際是中浪費,也是一種威脅,因為一旦黑客利用這個漏洞不斷侵蝕磁盤資源,計算機就崩潰了。所以說,文件系統(tǒng)肯定會做相應的處理,下面我就來驗證一下。
用ls來展現(xiàn)兩個文件:
我們在用du來展現(xiàn)兩個文件(du命令用于報告文件所使用的磁盤空間總量):
可以看到,用ls展現(xiàn)的空洞和非空洞的大小完全相同,而用du命令展現(xiàn)的則有差別,一個占用了8個1024的字節(jié)塊,而一個占用了16個1024的字節(jié)塊。這里有個問題,文件大小為15014,算下來最多就15個block,為什么是16個呢?在《APUE》中有這樣的解釋:"文件系統(tǒng)使用了若干塊以存放指向?qū)嶋H數(shù)據(jù)塊的各個指針"。
為什么會這樣呢?原因是ls展現(xiàn)的文件的邏輯大小,也就是文件在文件系統(tǒng)表現(xiàn)出來的大小,而du展現(xiàn)的是文件物理大小,也就是文件在磁盤上實際所占的block數(shù)。所以說,空洞文件在文件系統(tǒng)表現(xiàn)的還是和普通文件一樣的,但是實際上文件系統(tǒng)并沒有給他分配所表現(xiàn)出來的那么多空間,只是存放了有用的信息。
接下倆我們再來看一個現(xiàn)象:
首先我們用cat來輸出空洞文件中內(nèi)容,然后重定向到一個新的文件中:
我們再來用cp去復制一個文件:
可以看到,用cat得到的文件,文件實際占用的block增加了,而cp的沒有。那是因為cat在復制空洞文件時會將空洞補齊,將空洞填以0,因為cat命令就是簡單的read和write的操作,read在遇到空洞時讀出0,write則寫入0,這時文件就變成了非空洞文件,而cp在復制文件時不會,cp命令會去判斷文件是否有空洞,如果有,則會調(diào)用lseek進行空洞的模擬,所以還是會保持和源文件的一致性。
4.空洞文件有什么用?
空洞文件作用很大,例如迅雷下載文件,在未下載完成時就已經(jīng)占據(jù)了全部文件大小的空間,這時候就是空洞文件。下載時如果沒有空洞文件,多線程下載時文件就都只能從一個地方寫入,這就不是多線程了。如果有了空洞文件,可以從不同的地址寫入,就完成了多線程的優(yōu)勢任務(wù)。
感覺這并不是空洞文件的全部作用,后續(xù)將進行補充。。。。
總結(jié)
以上是生活随笔為你收集整理的Linux文件空洞与稀疏文件的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TCP/IP校验和(浅析+实例)
- 下一篇: Linux 源码安装 Python3 和