1. 程式人生 > >設計一個檔案系統,需要考慮哪些因素?

設計一個檔案系統,需要考慮哪些因素?

## 檔案系統的實現 在對檔案有了基本認識之後,現在是時候把目光轉移到檔案系統的`實現`上了。之前使用者關心的一直都是檔案是怎樣命名的、可以進行哪些操作、目錄樹是什麼,如何找到正確的檔案路徑等問題。而設計人員關心的是檔案和目錄是怎樣儲存的、磁碟空間是如何管理的、如何使檔案系統得以流暢執行的問題,下面我們就來一起討論一下這些問題。 ### 檔案系統佈局 檔案系統儲存在`磁碟`中。大部分的磁碟能夠劃分出一到多個分割槽,叫做`磁碟分割槽(disk partitioning)` 或者是`磁碟分片(disk slicing)`。每個分割槽都有獨立的檔案系統,每塊分割槽的檔案系統可以不同。磁碟的 0 號分割槽稱為 `主引導記錄(Master Boot Record, MBR)`,用來`引導(boot)` 計算機。在 MBR 的結尾是`分割槽表(partition table)`。每個分割槽表給出每個分割槽由開始到結束的地址。系統管理員使用一個稱為分割槽編輯器的程式來建立,調整大小,刪除和操作分割槽。這種方式的一個缺點是很難適當調整分割槽的大小,導致一個分割槽具有很多可用空間,而另一個分割槽幾乎完全被分配。 >MBR 可以用在 DOS 、Microsoft Windows 和 Linux 作業系統中。從 2010 年代中期開始,大多數新計算機都改用 GUID 分割槽表(GPT)分割槽方案。 下面是一個用 `GParted` 進行分割槽的磁碟,表中的分割槽都被認為是 `活動的(active)`。 ![](https://img2020.cnblogs.com/blog/1515111/202003/1515111-20200318150401073-320445598.png) 當計算機開始引 boot 時,BIOS 讀入並執行 MBR。 #### 引導塊 MBR 做的第一件事就是`確定活動分割槽`,讀入它的第一個塊,稱為`引導塊(boot block)` 並執行。引導塊中的程式將載入分割槽中的作業系統。為了一致性,每個分割槽都會從引導塊開始,即使引導塊不包含作業系統。引導塊佔據檔案系統的前 4096 個位元組,從磁碟上的位元組偏移量 0 開始。引導塊可用於啟動作業系統。 >在計算機中,引導就是啟動計算機的過程,它可以通過硬體(例如按下電源按鈕)或者軟體命令的方式來啟動。開機後,電腦的 CPU 還不能執行指令,因為此時沒有軟體在主存中,所以一些軟體必須先被載入到記憶體中,然後才能讓 CPU 開始執行。也就是計算機開機後,首先會進行軟體的裝載過程。 > >重啟電腦的過程稱為`重新引導(rebooting)`,從休眠或睡眠狀態返回計算機的過程不涉及啟動。 除了從引導塊開始之外,磁碟分割槽的佈局是隨著檔案系統的不同而變化的。通常檔案系統會包含一些屬性,如下 ![](https://img2020.cnblogs.com/blog/1515111/202003/1515111-20200318150413150-1964290340.png) #### 超級塊 緊跟在引導塊後面的是 `超級塊(Superblock)`,超級塊 的大小為 4096 位元組,從磁碟上的位元組偏移 4096 開始。超級塊包含檔案系統的所有關鍵引數 * 檔案系統的大小 * 檔案系統中的資料塊數 * 指示檔案系統狀態的標誌 * 分配組大小 在計算機啟動或者檔案系統首次使用時,超級塊會被讀入記憶體。 #### 空閒空間塊 接著是檔案系統中`空閒塊`的資訊,例如,可以用點陣圖或者指標列表的形式給出。 **BitMap 點陣圖或者 Bit vector 位向量** 點陣圖或位向量是一系列位或位的集合,其中每個位對應一個磁碟塊,該位可以採用兩個值:0和1,0表示已分配該塊,而1表示一個空閒塊。下圖中的磁碟上給定的磁碟塊例項(分配了綠色塊)可以用16位的位圖表示為:0000111000000110。 ![](https://img2020.cnblogs.com/blog/1515111/202003/1515111-20200318150425160-1090077003.png) **使用連結串列進行管理** 在這種方法中,空閒磁碟塊連結在一起,即一個空閒塊包含指向下一個空閒塊的指標。第一個磁碟塊的塊號儲存在磁碟上的單獨位置,也快取在記憶體中。 ![](https://img2020.cnblogs.com/blog/1515111/202003/1515111-20200318150435470-1272479312.png) #### 碎片 這裡不得不提一個叫做`碎片(fragment)`的概念,也稱為片段。一般零散的單個數據通常稱為片段。 磁碟塊可以進一步分為固定大小的分配單元,片段只是在驅動器上彼此不相鄰的檔案片段。如果你不理解這個概念就給你舉個例子。比如你用 Windows 電腦建立了一個檔案,你會發現這個檔案可以儲存在任何地方,比如存在桌面上,存在磁碟中的資料夾中或者其他地方。你可以開啟檔案,編輯檔案,刪除檔案等等。你可能以為這些都在一個地方發生,但是實際上並不是,你的硬碟驅動器可能會將檔案中的一部分儲存在一個區域內,另一部分儲存在另外一個區域,在你開啟檔案時,硬碟驅動器會迅速的將檔案的所有部分彙總在一起,以便其他計算機系統可以使用它。 ![](https://img2020.cnblogs.com/blog/1515111/202003/1515111-20200318150446418-2117150363.png) #### inode 然後在後面是一個 `inode(index node)`,也稱作索引節點。它是一個數組的結構,每個檔案有一個 inode,inode 非常重要,它說明了檔案的方方面面。每個索引節點都儲存物件資料的屬性和磁碟塊位置 有一種簡單的方法可以找到它們 `ls -lai` 命令。讓我們看一下根檔案系統: ![](https://img2020.cnblogs.com/blog/1515111/202003/1515111-20200318150455600-1208001258.png) inode 節點主要包括了以下資訊 * 模式/許可權(保護) * 所有者 ID * 組 ID * 檔案大小 * 檔案的硬連結數 * 上次訪問時間 * 最後修改時間 * inode 上次修改時間 檔案分為兩部分,索引節點和塊。一旦建立後,每種型別的塊數是固定的。你不能增加分割槽上 inode 的數量,也不能增加磁碟塊的數量。 緊跟在 inode 後面的是根目錄,它存放的是檔案系統目錄樹的根部。最後,磁碟的其他部分存放了其他所有的目錄和檔案。 ### 檔案的實現 最重要的問題是記錄各個檔案分別用到了哪些磁碟塊。不同的系統採用了不同的方法。下面我們會探討一下這些方式。分配背後的主要思想是`有效利用檔案空間`和`快速訪問檔案` ,主要有三種分配方案 * 連續分配 * 連結串列分配 * 索引分配 #### 連續分配 最簡單的分配方案是把每個檔案作為一連串連續資料塊儲存在磁碟上。因此,在具有 1KB 塊的磁碟上,將為 50 KB 檔案分配 50 個連續塊。 ![](https://img2020.cnblogs.com/blog/1515111/202003/1515111-20200318150508822-1376173759.png) 上面展示了 40 個連續的記憶體塊。從最左側的 0 塊開始。初始狀態下,還沒有裝載檔案,因此磁碟是空的。接著,從磁碟開始處(塊 0 )處開始寫入佔用 4 塊長度的記憶體 A 。然後是一個佔用 6 塊長度的記憶體 B,會直接在 A 的末尾開始寫。 注意每個檔案都會在新的檔案塊開始寫,所以如果檔案 A 只佔用了 `3 又 1/2` 個塊,那麼最後一個塊的部分記憶體會被浪費。在上面這幅圖中,總共展示了 7 個檔案,每個檔案都會從上個檔案的末尾塊開始寫新的檔案塊。 連續的磁碟空間分配有兩個優點。 * 第一,連續檔案儲存實現起來比較簡單,只需要記住兩個數字就可以:一個是第一個塊的檔案地址和檔案的塊數量。給定第一個塊的編號,可以通過簡單的加法找到任何其他塊的編號。 * 第二點是讀取效能比較強,可以通過一次操作從檔案中讀取整個檔案。只需要一次尋找第一個塊。後面就不再需要尋道時間和旋轉延遲,所以資料會以全頻寬進入磁碟。 因此,連續的空間分配具有`實現簡單`、`高效能`的特點。 不幸的是,連續空間分配也有很明顯的不足。隨著時間的推移,磁碟會變得很零碎。下圖解釋了這種現象 ![](https://img2020.cnblogs.com/blog/1515111/202003/1515111-20200318150519599-725681571.png) 這裡有兩個檔案 D 和 F 被刪除了。當刪除一個檔案時,此檔案所佔用的塊也隨之釋放,就會在磁碟空間中留下一些空閒塊。磁碟並不會在這個位置擠壓掉空閒塊,因為這會複製空閒塊之後的所有檔案,可能會有上百萬的塊,這個量級就太大了。 剛開始的時候,這個碎片不是問題,因為每個新檔案都會在之前檔案的結尾處進行寫入。然而,磁碟最終會被填滿,**因此要麼壓縮磁碟、要麼重新使用空閒塊的空間**。壓縮磁碟的開銷太大,因此不可行;後者會維護一個空閒列表,這個是可行的。但是這種情況又存在一個問題,為空閒塊匹配合適大小的檔案,需要知道該檔案的`最終大小`。 想象一下這種設計的結果會是怎樣的。使用者啟動 word 程序建立文件。應用程式首先會詢問最終建立的文件會有多大。這個問題必須回答,否則應用程式就不會繼續執行。如果空閒塊的大小要比檔案的大小小,程式就會終止。因為所使用的磁碟空間已經滿了。那麼現實生活中,有沒有使用連續分配記憶體的介質出現呢? `CD-ROM` 就廣泛的使用了連續分配方式。 >`CD-ROM(Compact Disc Read-Only Memory)`即只讀光碟,也稱作只讀儲存器。是一種在電腦上使用的光碟。這種光碟只能寫入資料一次,資訊將永久儲存在光碟上,使用時通過光碟驅動器讀出資訊。 ![](https://img2020.cnblogs.com/blog/1515111/202003/1515111-20200318150530072-1813980507.png) 然而 DVD 的情況會更加複雜一些。原則上,一個 `90分鐘` 的電影能夠被編碼成一個獨立的、大約 4.5 GB 的檔案。但是檔案系統所使用的 `UDF(Universal Disk Format)` 格式,使用一個 30 位的數來代表檔案長度,從而把檔案大小限制在 1 GB。所以,DVD 電影一般儲存在 3、4個連續的 1 GB 空間內。這些構成單個電影中的檔案塊稱為`擴充套件區(extends)`。 就像我們反覆提到的,**歷史總是驚人的相似**,許多年前,連續分配由於其`簡單`和`高效能`被實際使用在磁碟檔案系統中。後來由於使用者不希望在建立檔案時指定檔案的大小,於是放棄了這種想法。但是隨著 CD-ROM 、DVD、藍光光碟等光學介質的出現,連續分配又流行起來。從而得出結論,`技術永遠沒有過時性`,現在看似很老的技術,在未來某個階段可能又會流行起來。 #### 連結串列分配 第二種儲存檔案的方式是為每個檔案構造磁碟塊連結串列,每個檔案都是磁碟塊的連結列表,就像下面所示 ![](https://img2020.cnblogs.com/blog/1515111/202003/1515111-20200318150539449-809402370.png) 每個塊的第一個字作為指向下一塊的指標,塊的其他部分存放資料。如果上面這張圖你看的不是很清楚的話,可以看看整個的連結串列分配方案 ![](https://img2020.cnblogs.com/blog/1515111/202003/1515111-20200318151043192-1322693051.png) 與連續分配方案不同,這一方法可以充分利用每個磁碟塊。除了最後一個磁碟塊外,不會因為磁碟碎片而浪費儲存空間。同樣,在目錄項中,只要儲存了第一個檔案塊,那麼其他檔案塊也能夠被找到。 另一方面,在連結串列的分配方案中,儘管順序讀取非常方便,但是隨機訪問卻很困難(這也是陣列和連結串列資料結構的一大區別)。 還有一個問題是,由於指標會佔用一些位元組,每個磁碟塊實際儲存資料的位元組數並不再是 2 的整數次冪。雖然這個問題並不會很嚴重,但是這種方式降低了程式執行效率。許多程式都是以長度為 2 的整數次冪來讀寫磁碟,由於每個塊的前幾個位元組被指標所使用,所以要讀出一個完成的塊大小資訊,就需要當前塊的資訊和下一塊的資訊拼湊而成,因此就引發了查詢和拼接的開銷。 #### 使用記憶體表進行連結串列分配 由於連續分配和連結串列分配都有其不可忽視的缺點。所以提出了使用記憶體中的表來解決分配問題。取出每個磁碟塊的指標字,把它們放在記憶體的一個表中,就可以解決上述連結串列的兩個不足之處。下面是一個例子 ![](https://img2020.cnblogs.com/blog/1515111/202003/1515111-20200318151058517-1386577323.png) 上圖表示了連結串列形成的磁碟塊的內容。這兩個圖中都有兩個檔案,檔案 A 依次使用了磁碟塊地址 **4、7、 2、 10、 12**,檔案 B 使用了**6、3、11 和 14**。也就是說,檔案 A 從地址 4 處開始,順著連結串列走就能找到檔案 A 的全部磁碟塊。同樣,從第 6 塊開始,順著鏈走到最後,也能夠找到檔案 B 的全部磁碟塊。你會發現,這兩個連結串列都以不屬於有效磁碟編號的特殊標記(-1)結束。記憶體中的這種表格稱為 `檔案分配表(File Application Table,FAT)`。 使用這種組織方式,整個塊都可以存放資料。進而,隨機訪問也容易很多。雖然仍要順著鏈在記憶體中查詢給定的偏移量,但是整個鏈都存放在記憶體中,所以不需要任何磁碟引用。與前面的方法相同,不管檔案有多大,在目錄項中只需記錄一個整數(起始塊號),按照它就可以找到檔案的全部塊。 這種方式存在缺點,那就是**必須要把整個連結串列放在記憶體中**。對於 1TB 的磁碟和 1KB 的大小的塊,那麼這張表需要有 10 億項。。。每一項對應於這 10 億個磁碟塊中的一塊。每項至少 3 個位元組,為了提高查詢速度,有時需要 4 個位元組。根據系統對空間或時間的優化方案,這張表要佔用 3GB 或 2.4GB 的記憶體。FAT 的管理方式不能較好地擴充套件並應用於大型磁碟中。而這正是最初 MS-DOS 檔案比較實用,並仍被各個 Windows 版本所安全支援。 #### inode 最後一個記錄各個檔案分別包含哪些磁碟塊的方法是給每個檔案賦予一個稱為 `inode(索引節點)` 的資料結構,每個檔案都與一個 `inode` 進行關聯,inode 由整數進行標識。 下面是一個簡單例子的描述。 ![](https://img2020.cnblogs.com/blog/1515111/202003/1515111-20200318151107568-1879043627.png) 給出 inode 的長度,就能夠找到檔案中的所有塊。 相對於在記憶體中使用表的方式而言,這種機制具有很大的優勢。即只有在檔案開啟時,其 inode 才會在記憶體中。如果每個 inode 需要 n 個位元組,最多 k 個檔案同時開啟,那麼 inode 佔有總共開啟的檔案是 kn 位元組。僅需預留這麼多空間。 這個陣列要比我們上面描述的 `FAT(檔案分配表)` 佔用的空間小的多。原因是用於儲存所有磁碟塊的連結列表的表的大小與磁碟本身成正比。如果磁碟有 n 個塊,那麼這個表也需要 n 項。隨著磁碟空間的變大,那麼該表也隨之`線性增長`。相反,inode 需要節點中的陣列,其大小和可能需要開啟的最大檔案個數成正比。它與磁碟是 100GB、4000GB 還是 10000GB 無關。 inode 的一個問題是如果每個節點都會有固定大小的磁碟地址,那麼檔案增長到所能允許的最大容量外會發生什麼?一個解決方案是**最後一個磁碟地址不指向資料塊**,而是**指向一個包含額外磁碟塊地址的地址**,如上圖所示。一個更高階的解決方案是:有兩個或者更多包含磁碟地址的塊,或者指向其他存放地址的磁碟塊的磁碟塊。Windows 的 NTFS 檔案系統採用了相似的方法,所不同的僅僅是大的 inode 也可以表示小的檔案。 >NTFS 的全稱是 `New Technology File System`,是微軟公司開發的專用系統檔案,NTFS 取代 FAT(檔案分配表) 和 `HPFS(高效能檔案系統)` ,並在此基礎上進一步改進。例如增強對元資料的支援,使用更高階的資料結構以提升效能、可靠性和磁碟空間利用率等。 ### 目錄的實現 檔案只有開啟後才能夠被讀取。在檔案開啟後,作業系統會使用使用者提供的路徑名來定位磁碟中的目錄。目錄項提供了查詢檔案磁碟塊所需要的資訊。根據系統的不同,提供的資訊也不同,可能提供的資訊是整個檔案的磁碟地址,或者是第一個塊的數量(兩個連結串列方案)或 inode的數量。不過不管用那種情況,目錄系統的主要功能就是 **將檔案的 ASCII 碼的名稱對映到定位資料所需的資訊上**。 與此關係密切的問題是屬性應該存放在哪裡。每個檔案系統包含不同的檔案屬性,例如檔案的所有者和建立時間,需要儲存的位置。一種顯而易見的方法是直接**把檔案屬性存放在目錄中**。有一些系統恰好是這麼做的,如下。 ![](https://img2020.cnblogs.com/blog/1515111/202003/1515111-20200318151532841-564771010.png) 在這種簡單的設計中,目錄有一個固定大小的目錄項列表,每個檔案對應一項,其中包含一個固定長度的檔名,檔案屬性的結構體以及用以說明磁碟塊位置的一個或多個磁碟地址。 對於採用 inode 的系統,會把 inode 儲存在屬性中而不是目錄項中。在這種情況下,目錄項會更短:僅僅只有檔名稱和 inode 數量。這種方式如下所示 ![](https://img2020.cnblogs.com/blog/1515111/202003/1515111-20200318151541598-495680164.png) 到目前為止,我們已經假設檔案具有較短的、固定長度的名字。在 MS-DOS 中,具有 1 - 8 個字元的基本名稱和 1 - 3 個字元的可拓展名稱。在 UNIX 版本 7 中,檔案有 1 - 14 個字元,包括任何拓展。然而,幾乎所有的現代作業系統都支援可變長度的副檔名。這是如何實現的呢? 最簡單的方式是給予檔名一個長度限制,比如 255 個字元,然後使用上圖中的設計,併為每個檔名保留 255 個字元空間。這種處理很簡單,但是浪費了大量的目錄空間,因為只有很少的檔案會有那麼長的檔名稱。所以,需要一種其他的結構來處理。 一種可選擇的方式是放棄所有目錄項大小相同的想法。在這種方法中,每個目錄項都包含一個固定部分,這個固定部分通常以目錄項的長度開始,後面是固定格式的資料,通常包括**所有者、建立時間、保護資訊和其他屬性**。這個固定長度的頭的後面是一個任意長度的實際檔名,如下圖所示 ![](https://img2020.cnblogs.com/blog/1515111/202003/1515111-20200318151550284-1724060342.png) 上圖是 SPARC 機器使用正序放置。 >處理機中的一串字元存放的順序有`正序(big-endian)` 和`逆序(little-endian)` 之分。正序存放的就是高位元組在前低位元組在後,而逆序存放的就是低位元組在前高位元組在後。 這個例子中,有三個檔案,分別是 `project-budget`、`personnel` 和 `foo`。每個檔名以一個特殊字元(通常是 0 )結束,用矩形中的叉進行表示。為了使每個目錄項從字的邊界開始,每個檔名被填充成整數個字,如下圖所示 ![](https://img2020.cnblogs.com/blog/1515111/202003/1515111-20200318151735376-863181431.png) 這個方法的缺點是當檔案被移除後,就會留下一塊固定長度的空間,而新新增進來的檔案大小不一定和空閒空間大小一致。 ![](https://img2020.cnblogs.com/blog/1515111/202003/1515111-20200318151744736-200015973.png) 這個問題與我們上面探討的連續磁碟檔案的問題是一樣的,由於整個目錄在記憶體中,所以只有對目錄進行`緊湊拼接`操作才可節省空間。另一個問題是,一個目錄項可能會分佈在多個頁上,**在讀取檔名時可能發生缺頁中斷**。 處理可變長度檔名字的另外一種方法是,使目錄項自身具有固定長度,而將檔名放在目錄末尾的堆疊中。如上圖所示的這種方式。這種方法的優點是當目錄項被移除後,下一個檔案將能夠正常匹配移除檔案的空間。當然,必須要對`堆`進行管理,因為在處理檔名的時候也會發生缺頁異常。 到目前為止的所有設計中,在需要查詢檔名時,所有的方案都是線性的從頭到尾對目錄進行搜尋。對於特別長的目錄,線性搜尋的效率很低。提高檔案檢索效率的一種方式是在每個目錄上使用`雜湊表(hash table)`,也叫做散列表。我們假設表的大小為 n,在輸入檔名時,檔名被雜湊在 0 和 n - 1 之間,例如,它被 n 除,並取餘數。或者對構成檔名字的字求和或類似某種方法。 無論採用哪種方式,**在新增一個檔案時都要對與雜湊值相對應的散列表進行檢查**。如果沒有使用過,就會將一個指向目錄項的指標指向這裡。檔案目錄項緊跟著雜湊表後面。如果已經使用過,就會構造一個連結串列(這種構造方式是不是和 HashMap 使用的資料結構一樣?),連結串列的表頭指標存放在表項中,並通過雜湊值將所有的表項相連。 ![](https://img2020.cnblogs.com/blog/1515111/202003/1515111-20200318151753972-2143036040.png) 查詢檔案的過程和新增類似,首先對檔名進行雜湊處理,在雜湊表中查詢是否有這個雜湊值,如果有的話,就檢查這條鏈上所有的雜湊項,檢視檔名是否存在。如果雜湊不在鏈上,那麼檔案就不在目錄中。 使用雜湊表的優勢是`查詢非常迅速`,缺點是`管理起來非常複雜`。只有在系統中會有成千上萬個目錄項存在時,才會考慮使用散列表作為解決方案。 另外一種在大量目錄中加快查詢指令目錄的方法是使用`快取`,快取查詢的結果。在開始查詢之前,會首先檢查檔名是否在快取中。如果在快取中,那麼檔案就能立刻定位。當然,只有在較少的檔案下進行多次查詢,快取才會發揮最大功效。 ### 共享檔案 當多個使用者在同一個專案中工作時,他們通常需要共享檔案。如果這個共享檔案同時出現在多個使用者目錄下,那麼他們協同工作起來就很方便。下面的這張圖我們在上面提到過,但是有一個更改的地方,就是 **C 的一個檔案也出現在了 B 的目錄下**。 ![](https://img2020.cnblogs.com/blog/1515111/202003/1515111-20200318151805611-1436072361.png) 如果按照如上圖的這種組織方式而言,那麼 B 的目錄與該共享檔案的聯絡稱為 `連結(link)`。那麼檔案系統現在就是一個 `有向無環圖(Directed Acyclic Graph, 簡稱 DAG)`,而不是一棵樹了。 >在圖論中,如果一個有向圖從任意頂點出發無法經過若干條邊回到該點,則這個圖是一個`有向無環圖`,我們不會在此著重探討關於圖論的東西,大家可以自行 google。 將檔案系統組織成為有向無環圖會使得維護複雜化,但也是必須要付出的代價。 `共享檔案`很方便,但這也會帶來一些問題。如果目錄中包含磁碟地址,則當連結檔案時,**必須把 C 目錄中的磁碟地址複製到 B 目錄中**。如果 B 或者 C 隨後又向檔案中新增內容,則僅在執行追加的使用者的目錄中顯示新寫入的資料塊。這種變更將會對其他使用者不可見,從而破壞了共享的目的。 ![](https://img2020.cnblogs.com/blog/1515111/202003/1515111-20200318151815665-1696801367.png) 有兩種方案可以解決這種問題。 * 第一種解決方案,磁碟塊不列入目錄中,而是會把磁碟塊放在與檔案本身相關聯的小型資料結構中。目錄將指向這個小型資料結構。這是 `UNIX` 中使用的方式(小型資料結構就是 inode)。 * 在第二種解決方案中,通過讓系統建立一個型別為 `LINK` 的新檔案,並把該檔案放在 B 的目錄下,使得 B 與 C 建立連結。新的檔案中只包含了它所連結的檔案的路徑名。當 B 想要讀取檔案時,作業系統會檢查 B 的目錄下存在一個型別為 LINK 的檔案,進而找到該連結的檔案和路徑名,然後再去讀檔案,這種方式稱為 `符號連結(symbolic linking)`。 ![](https://img2020.cnblogs.com/blog/1515111/202003/1515111-20200318151826904-1996232451.png) 上面的每一種方法都有各自的缺點,在第一種方式中,B 連結到共享檔案時,inode 記錄檔案的所有者為 C。**建立一個連結並不改變所有關係**,如下圖所示。 ![](https://img2020.cnblogs.com/blog/1515111/202003/1515111-20200318151837629-1392900508.png) 第一開始的情況如圖 a 所示,此時 C 的目錄的所有者是 C ,當目錄 B 連結到共享檔案時,並不會改變 C 的所有者關係,只是把計數 + 1,所以此時 **系統知道目前有多少個目錄指向這個檔案**。然後 C 嘗試刪除這個檔案,這個時候有個問題,如果 C 把檔案移除並清除了 inode 的話,那麼 B 會有一個目錄項指向無效的節點。如果 inode 以後分配給另一個檔案,則 B 的連結指向一個錯誤的檔案。系統通過 inode 可知檔案仍在被引用,但是沒有辦法找到該檔案的全部目錄項以刪除它們。指向目錄的指標不能儲存在 inode 中,原因是有可能有無數個這樣的目錄。 所以我們能做的就是刪除 C 的目錄項,但是將 inode 保留下來,並將計數設定為 1 ,如上圖 c 所示。c 表示的是隻有 B 有指向該檔案的目錄項,而該檔案的前者是 C 。如果系統進行記賬操作的話,那麼 C 將繼續為該檔案付賬直到 B 決定刪除它,如果是這樣的話,只有到計數變為 0 的時刻,才會刪除該檔案。 對於`符號連結`,以上問題不會發生,只有真正的檔案所有者才有一個指向 inode 的指標。連結到該檔案上的使用者只有路徑名,沒有指向 inode 的指標。當檔案所有者刪除檔案時,該檔案被銷燬。以後若試圖通過符號連結訪問該檔案將會失敗,因為系統不能找到該檔案。刪除符號連結不會影響該檔案。 符號連結的問題是**需要額外的開銷**。必須讀取包含路徑的檔案,然後要一個部分接一個部分地掃描路徑,直到找到 inode 。這些操作也許需要很多次額外的磁碟訪問。此外,每個符號連結都需要額外的 inode ,以及額外的一個磁碟塊用於儲存路徑,雖然如果路徑名很短,作為一種優化,系統可以將它儲存在 inode 中。符號連結有一個優勢,即只要**簡單地提供一個機器的網路地址以及檔案在該機器上駐留的路徑**,就可以連線全球任何地方機器上的檔案。 還有另一個由連結帶來的問題,在符號連結和其他方式中都存在。如果允許連結,檔案有兩個或多個路徑。查詢一指定目錄及其子目錄下的全部檔案的程式將多次定位到被連結的檔案。例如,一個將某一目錄及其子目錄下的檔案轉存到磁帶上的程式有可能多次複製一個被連結的檔案。進而,如果接著把磁帶讀入另一臺機器,除非轉出程式具有智慧,否則被連結的檔案將被兩次複製到磁碟上,而不是隻是被連結起來。 相關參考: https://zhuanlan.zhihu.com/p/41358013 https://www.linuxtoday.com/blog/what-is-an-inode.html https://www.lifewire.com/what-is-fragmentation-defragmentation-2625884 https://www.geeksforgeeks.org/free-space-management-in-operating-system/ https://sites.ualberta.ca/dept/chemeng/AIX-43/share/man/info/C/a_doc_lib/aixprggd/genprogc/fsyslayout.htm https://en.wikipedia.org/wiki/Disk_partitioning https://en.wikipedia.org/wiki/Master_boot_record https://en.wikipedia.org/wiki/Booting https://www.computerhope.com/jargon/f/fileprot.htm https://en.wikipedia.org/wiki/File_attribute https://en.wikipedia.org/wiki/Make_(software) https://unix.stackexchange.com/questions/60034/what-are-character-special-and-block-special-files-in-a-unix-system https://www.computerhope.com/jargon/d/director.htm https://www.computerhope.com/jargon/r/regular-file.htm https://baike.baidu.com/item/固態硬碟/453510?fr=aladdin 《現代作業系統》第四版 《Modern Operation System》fourth ![](https://img2020.cnblogs.com/blog/1515111/202003/1515111-20200318151957595-7285914