Linux文件管理從用戶的層面介紹了Linux管理文件的方式。Linux有一個樹狀結構來組織文件。樹的頂端爲根目錄(/),節點爲目錄,而末端的葉子爲包含數據的文件。當咱們給出一個文件的完整路徑時,咱們從根目錄出發,通過沿途各個目錄,最終到達文件。html
咱們能夠對文件進行許多操做,好比打開和讀寫。在Linux文件管理相關命令中,咱們看到許多對文件進行操做的命令。它們大都基於對文件的打開和讀寫操做。好比cat能夠打開文件,讀取數據,最後在終端顯示:node
$cat test.txt
對於Linux下的程序員來講,瞭解文件系統的底層組織方式,是深刻進行系統編程所必備的。即便是普通的Linux用戶,也能夠根據相關的內容,設計出更好的系統維護方案。程序員
文件系統的最終目的是把大量數據有組織的放入持久性(persistant)的存儲設備中,好比硬盤和磁盤。這些存儲設備與內存不一樣。它們的存儲能力具備持久性,不會由於斷電而消失;存儲量大,但讀取速度慢。編程
觀察常見存儲設備。最開始的區域是MBR,用於Linux開機啓動(參考Linux開機啓動)。剩餘的空間可能分紅數個分區(partition)。每一個分區有一個相關的分區表(Partition table),記錄分區的相關信息。這個分區表是儲存在分區以外的。分區表說明了對應分區的起始位置和分區的大小。segmentfault
咱們在Windows系統經常看到C分區、D分區等。Linux系統下也能夠有多個分區,但都被掛載在同一個文件系統樹上。數組
數據被存入到某個分區中。一個典型的Linux分區(partition)包含有下面各個部分:spa
分區的第一個部分是啓動區(Boot block),它主要是爲計算機開機服務的。Linux開機啓動後,會首先載入MBR,隨後MBR從某個硬盤的啓動區加載程序。該程序負責進一步的操做系統的加載和啓動。爲了方便管理,即便某個分區中沒有安裝操做系統,Linux也會在該分區預留啓動區。操作系統
啓動區以後的是超級區(Super block)。它存儲有文件系統的相關信息,包括文件系統的類型,inode的數目,數據塊的數目。設計
隨後是多個inodes,它們是實現文件存儲的關鍵。在Linux系統中,一個文件能夠分紅幾個數據塊存儲,就好像是分散在各地的龍珠同樣。爲了順利的收集齊龍珠,咱們須要一個「雷達」的指引:該文件對應的inode。每一個文件對應一個inode。這個inode中包含多個指針,指向屬於該文件各個數據塊。當操做系統須要讀取文件時,只須要對應inode的"地圖",收集起分散的數據塊,就能夠收穫咱們的文件了。指針
最後一部分,就是真正儲存數據的數據塊們(data blocks)了。
上面咱們看到了存儲設備的宏觀結構。咱們要深刻到分區的結構,特別是文件在分區中的存儲方式。
文件是文件系統對數據的分割單元。文件系統用目錄來組織文件,賦予文件以上下分級的結構。在硬盤上實現這一分級結構的關鍵,是使用inode來虛擬普通文件和目錄文件對象。
在Linux文件管理中,咱們知道,一個文件除了自身的數據以外,還有一個附屬信息,即文件的元數據(metadata)。這個元數據用於記錄文件的許多信息,好比文件大小,擁有人,所屬的組,修改日期等等。元數據並不包含在文件的數據中,而是由操做系統維護的。事實上,這個所謂的元數據就包含在inode中。咱們能夠用$ls -l filename來查看這些元數據。正如咱們上面看到的,inode所佔據的區域與數據塊的區域不一樣。每一個inode有一個惟一的整數編號(inode number)表示。
在保存元數據,inode是「文件」從抽象到具體的關鍵。正如上一節中提到的,inode儲存由一些指針,這些指針指向存儲設備中的一些數據塊,文件的內容就儲存在這些數據塊中。當Linux想要打開一個文件時,只須要找到文件對應的inode,而後沿着指針,將全部的數據塊收集起來,就能夠在內存中組成一個文件的數據了。
數據塊在1, 32, 0, ...
inode並非組織文件的惟一方式。最簡單的組織文件的方法,是把文件依次順序的放入存儲設備,DVD就採起了相似的方式。但若是有刪除操做,刪除形成的空餘空間夾雜在正常文件之間,很難利用和管理。
複雜的方式可使用鏈表,每一個數據塊都有一個指針,指向屬於同一文件的下一個數據塊。這樣的好處是能夠利用零散的空餘空間,壞處是對文件的操做必須按照線性方式進行。若是想隨機存取,那麼必須遍歷鏈表,直到目標位置。因爲這一遍歷不是在內存進行,因此速度很慢。
FAT系統是將上面鏈表的指針取出,放入到內存的一個數組中。這樣,FAT能夠根據內存的索引,迅速的找到一個文件。這樣作的主要問題是,索引數組的大小與數據塊的總數相同。所以,存儲設備很大的話,這個索引數組會比較大。
inode既能夠充分利用空間,在內存佔據空間不與存儲設備相關,解決了上面的問題。但inode也有本身的問題。每一個inode可以存儲的數據塊指針總數是固定的。若是一個文件須要的數據塊超過這一總數,inode須要額外的空間來存儲多出來的指針。
在Linux中,咱們經過解析路徑,根據沿途的目錄文件來找到某個文件。目錄中的條目除了所包含的文件名,還有對應的inode編號。當咱們輸入$cat /var/test.txt時,Linux將在根目錄文件中找到var這個目錄文件的inode編號,而後根據inode合成var的數據。隨後,根據var中的記錄,找到text.txt的inode編號,沿着inode中的指針,收集數據塊,合成text.txt的數據。整個過程當中,咱們參考了三個inode:根目錄文件,var目錄文件,text.txt文件的inodes。
在Linux下,可使用$stat filename,來查詢某個文件對應的inode編號。
在存儲設備中實際上存儲爲:
當咱們讀取一個文件時,其實是在目錄中找到了這個文件的inode編號,而後根據inode的指針,把數據塊組合起來,放入內存供進一步的處理。當咱們寫入一個文件時,是分配一個空白inode給該文件,將其inode編號記入該文件所屬的目錄,而後選取空白的數據塊,讓inode的指針指像這些數據塊,並放入內存中的數據。
在Linux的進程中,當咱們打開一個文件時,返回的是一個文件描述符。這個文件描述符是一個數組的下標,對應數組元素爲一個指針。有趣的是,這個指針並無直接指向文件的inode,而是指向了一個文件表格,再經過該表格,指向加載到內存中的目標文件的inode。以下圖,一個進程打開了兩個文件。
能夠看到,每一個文件表格中記錄了文件打開的狀態(status flags),好比只讀,寫入等,還記錄了每一個文件的當前讀寫位置(offset)。當有兩個進程打開同一個文件時,能夠有兩個文件表格,每一個文件表格對應的打開狀態和當前位置不一樣,從而支持一些文件共享的操做,好比同時讀取。
要注意的是進程fork以後的狀況,子進程將只複製文件描述符的數組,而和父進程共享內核維護的文件表格和inode。此時要特別當心程序的編寫。
這裏歸納性的總結了Linux的文件系統。Linux以inode的方式,讓數據造成文件。
瞭解Linux的文件系統,是深刻了解操做系Linux原理的重要一步。
擴展閱讀:做者寫的《Linux的概念與體系》系列文章。
轉載自:Linux文件系統的實現 做者:Vamei