在計算機世界中,檔案是資料的抽象集合,它為使用者提供了一種直觀的方式來處理資料。而這些檔案的資料最終必須儲存在具體的物理裝置上,例如HDD、SSD 或是 USB。這些儲存裝置透過裝置控制器將他們的物理介質對映為一個巨大的、可隨機定址的地址空間,我們可以將其看作一個超大的陣列。一個裝置可以儲存多個檔案,那麼,如何將多個抽象的檔案對映到這一巨大空間上,就是一個非常重要的問題。檔案系統的設計在這裡起著至關重要的作用,它必須以合理的方式將檔案分佈到物理儲存介質上,以確儲存儲和訪問的高效性。本文將為您介紹幾種經典的檔案分配方式及其優缺點。
物理儲存的基本概念:塊與簇
當硬碟經過裝置控制器抽象為一個超大的陣列後,對於裝置來說,塊(block)通常是儲存介質的最小單元。每個塊有固定的大小,例如 4KB,由儲存介質本身決定。這些塊是儲存裝置的最小分配和管理單位。而為了更好地利用空間並減少管理開銷,在系統中,塊可以進一步組合成更大的儲存單位,稱為簇(cluster),通常簇由幾個連續的塊組成。通常在格式化時可以指定簇大小,之後就不再改變,一簇至少包含一個塊,也可以設定為包含多個塊。在格式化完成後,簇就成為檔案系統視角下的最小分配單位。
簇的大小直接影響到儲存效率和檔案系統的效能。大簇(如32KB或64KB)意味著每個簇可以容納更多資料,從而減少檔案系統管理這些簇的開銷,管理更容易且讀寫效能高,但會導致即使是 1 位元組的檔案也會佔用一簇,造成小檔案佔用過多空間的情況,導致內部碎片(internal fragmentation)。反之,小簇(如512位元組或4KB)可以減少內部碎片,但會增加管理簇的複雜性和處理開銷。因此,簇大小的選擇是權衡儲存效率與管理開銷的重要決策。
連續分配:最簡單卻難以擴充套件的方案
儲存器已經劃分為以簇編址的巨大陣列,而檔案也被劃分為幾簇,接下來我們要考慮怎樣為他們安排位置。
連續分配(Contiguous Allocation)是檔案系統中最簡單的物理分配方式。它將檔案儲存在一組連續的簇中。在檔案記錄中,只需要儲存檔案的起始位置和長度,這樣在訪問檔案時,只需要從起始位置開始,讀取指定長度的資料即可。由於連續分配的檔案在物理磁碟上是緊密排列的,因此它非常適合隨機訪問(random access),尤其是對大檔案的順序訪問時,效能表現十分優秀。當新增檔案時,直接找到可容納下檔案的連續塊插入即可。
然而,連續分配也有許多致命缺點:
- 外部碎片(External Fragmentation):隨著檔案不斷地建立和刪除,磁碟空間會被割裂為許多不連續的小塊,導致碎片化,最終可能出現雖然總空間足夠,但無法找到足夠連續空間分配給新檔案的情況。
- 檔案大小固定:由於檔案必須儲存在連續的空間中,因此檔案的大小在建立時就需要確定,且不能動態擴充套件。如果檔案需要增長,就可能會覆蓋其他檔案的資料。
- 頻繁的資料移動:如果檔案需要擴充套件而當前空間不足,就可能需要將檔案移動到其他更大的連續區域,這將導致大量的資料移動(data movement),耗費效能。
這些缺點使得連續分配在現代作業系統中很少使用,尤其是在面對高頻率的檔案操作時。然而,在某些特定情況下,例如對於磁帶這樣的順序訪問儲存介質(sequential access storage medium),連續分配仍然是有效的選擇。
簡單連結串列分配:解決碎片問題的嘗試
為了解決外部碎片的問題,一種改進的方法是連結串列分配(Linked Allocation)。在連結串列分配中,檔案被分為多個塊,每個塊透過一個指標連結到下一個塊,從而形成一個連結串列。檔案記錄只需要儲存檔案的第一個塊的地址(以及可能的最後一個塊地址),其餘的塊透過連結串列指標進行訪問。這樣離散的分配方式也就不再有外部碎片。
然而,連結串列分配也有明顯的缺點:
- 無法隨機訪問:由於塊之間透過指標連結,無法直接跳轉到某個特定塊,因此只能順序訪問(sequential access)檔案的內容。如果需要訪問檔案的某個特定位置,必須從頭開始遍歷整個連結串列。
- 可靠性問題:由於每個塊都透過指標連結,一旦某個塊的指標損壞,就會導致整個檔案的剩餘部分無法訪問。
- 儲存開銷:每個塊需要額外儲存一個指標,這增加了儲存開銷,檔案越小,這種額外開銷帶來的浪費越顯著。
連結串列分配解決了外部碎片的問題,但由於無法隨機訪問和儲存開銷大的缺點,使得它在現代作業系統中的應用也較為有限。
顯式連結串列分配:檔案分配表 (FAT)
在連結串列分配的基礎上,另一種改進方式是顯式連結串列分配(Explicit Linked Allocation),即將每個塊的指標資訊集(即下一塊)中儲存在一個專門的表中(而非儲存到每個塊中),這就是檔案分配表(File Allocation Table, FAT)。FAT 是一種將每一個簇和其後續簇的位置關係集中儲存的結構,透過查詢檔案的起始簇,可以逐步找到檔案的所有簇。
在 FAT 結構下,檔案記錄仍只需要儲存檔案的起始塊位置,然後透過 FAT 來找到其他塊的位置。這樣的設計使得在檔案內進行塊間跳轉變得更加方便,雖然 FAT 仍然不能真正實現隨機訪問,但跳轉速度相較於簡單連結串列分配要快得多。為了提高訪問速度,作業系統通常將 FAT 快取在記憶體中,從而在檔案訪問時減少對磁碟的頻繁讀取。
FAT 結構具有如下特點:
- 集中管理連結串列資訊:透過將所有簇的資訊集中管理,FAT 使得檔案的管理更加簡單,整個檔案系統只需要一張表,特別是在進行空間分配和回收時,能有效追蹤哪些簇是空閒的。
- 提高訪問效率:由於 FAT 可以被快取到記憶體中,檔案訪問的速度顯著提高,尤其是在檔案內部跳轉時。
- 檔案限制:簇大小和指標位數決定了單檔案大小的上限。假設一個 FAT 檔案系統使用 16 位指標來表示每個簇的位置,並且簇的大小為 4KB,那麼可以表示的最大簇數是 2^16 = 65536 個簇。因此,該檔案系統支援的最大檔案大小為 65536 * 4KB = 256MB。
FAT 系列檔案系統最早設計於 1977 年,歷經多次演化,至今仍有應用,特別是在嵌入式裝置和快閃記憶體裝置(如 USB 快閃記憶體)中。FAT 系列檔案系統(如 FAT16、FAT32)由於其簡單性和廣泛相容性,成為了很多嵌入式裝置的首選。exFAT 是微軟在 2006 年引入的一種新的檔案系統,專為快閃記憶體裝置設計,主要目的是在 FAT32 的基礎上克服其侷限性,相比上面介紹的原始版本擴充了很多功能,同時保持相容性。
索引分配:真正實現隨機訪問
在離散儲存的基礎上,顯然不一定要使用連結串列可以在檔案記錄中以變長陣列記錄每個塊的位置,這樣就可以實現真正的隨機訪問(random access)。這種陣列叫做索引(index),這種分配方式稱為索引分配(Indexed Allocation)。在索引分配中,檔案系統會為在每個檔案的檔案記錄裡維護其索引塊,索引塊中儲存了檔案各個資料塊的物理位置。透過查詢這個索引塊,作業系統可以直接定位到檔案的任意塊,從而實現快速的隨機訪問。簡單來說,索引用陣列實現就可以,也可以選擇二叉樹或雜湊表,這就不是本文的重點了。
單級索引(Single-Level Index)是最簡單的一種索引分配方式,其中每個檔案都有一個單獨的索引塊,記錄檔案的所有資料塊位置。這使得檔案的訪問變得非常靈活,特別是對於需要頻繁隨機訪問的場景,索引分配具有顯著的優勢。此外,由於索引塊集中儲存了所有的塊位置,檔案的增刪也變得更加容易,只需更新索引塊即可,無需對物理塊進行復雜的移動操作。
例如,假設一個單級索引系統,每個索引塊的大小為 4KB,且每個指標佔用 4 位元組,那麼一個索引塊最多可以容納 4KB / 4B = 1024 個指標。如果每個資料塊的大小也是 4KB,那麼這個檔案系統支援的最大檔案大小為 1024 * 4KB = 4MB。
由此可以看出,單級索引適用於中小型檔案。然而,索引塊的大小是有限的,這意味著單級索引的檔案大小上限很低,只能用於較小的檔案。對於非常大的檔案,則需要使用其他的多級索引方案。
多級索引
由於檔案記錄的大小通常是有限的,因此檔案系統引入了多級索引(Multi-Level Indexing)的概念,也叫間接索引。多級索引透過使用多個層次的索引塊來管理檔案的資料塊位置。例如,兩級索引(Two-Level Indexing)使用一個一級索引塊指向多個二級索引塊,而二級索引塊則記錄檔案的資料塊位置。這種設計使得檔案系統可以儲存比單級索引更大的檔案。
以二級索引為例子,檔案記錄中儲存的索引是一級索引,一級索引中指向的塊並非檔案本身,而是其他索引塊,叫做二級索引,由二級索引記錄檔案簇的物理位置。
混合索引:現代檔案系統的主流
多級索引提高了單檔案大小的上限,但是,如果檔案記錄中全部使用多級索引,即使只有 1 位元組的檔案,也至少需要佔用多級索引中每一級索引塊各一個。檔案越小,索引本身帶來的開銷越大。
現代檔案系統為了平衡小型檔案和大型檔案的儲存需求,引入了混合索引(Hybrid Indexing)的方式。混合索引結合了直接索引、間接索引和多級索引的優點。例如,在某些檔案系統中,檔案記錄中包含了一些直接指向資料塊的指標(適用於小檔案),以及間接指向索引塊的指標(適用於較大的檔案)。這種設計使得檔案系統能夠高效地處理各種不同大小的檔案,既能減少小檔案的管理開銷,又能支援大型檔案的高效存取。
例如,假設一個檔案系統使用混合索引的方式,每個 inode 包含 12 個直接指標、1 個一級間接指標、1 個二級間接指標以及 1 個三級間接指標。假設每個資料塊大小為 4KB,每個指標佔用 4 位元組。則:
- 直接指標:可以直接指向 12 個資料塊,儲存大小為 12 * 4KB = 48KB。即 48 KB 以下的檔案只需要單級索引。
- 一級間接指標:指向一個索引塊,該索引塊包含 4KB / 4B = 1024 個指標,每個指標指向一個資料塊,因此可以儲存 1024 * 4KB = 4MB 的資料。即 4 MB + 48 KB 以下的檔案只需要前兩級索引。
- 二級間接指標:指向一個索引塊,該索引塊中的每個指標又指向另一個索引塊,這樣可以指向 1024 * 1024 個資料塊,共計 1024 * 1024 * 4KB = 4GB 的資料。
- 三級間接指標:同樣道理,可以指向 1024 * 1024 * 1024 個資料塊,共計 1024 * 1024 * 1024 * 4KB = 4TB 的資料。
因此,該混合索引結構支援的最大檔案大小約為 48KB + 4MB + 4GB + 4TB。由此可以看出,混合索引的設計使得檔案系統既能夠高效地處理小型檔案,又可以支援非常大的檔案。
混合索引方式被廣泛應用於現代絕大多數檔案系統中,例如:
- NTFS(New Technology File System):是 Windows 作業系統的預設檔案系統,使用了混合索引結構來實現對檔案的靈活管理。
- HFS+(Hierarchical File System Plus):是 macOS 中曾經使用的檔案系統,透過索引節點和混合索引來管理檔案。
- APFS(Apple File System):是蘋果公司為 macOS、iOS 等裝置開發的新一代檔案系統,同樣使用了混合索引來提高檔案訪問的效率和靈活性。
- ext4(Fourth Extended File System):是 Linux 作業系統中的預設檔案系統,使用了混合索引結構,並透過擴充套件的多級索引和日誌機制來提高檔案的管理效率和可靠性。
混合索引結構的優勢在於其對小型檔案和大型檔案的適應性,使得檔案系統能夠在各種應用場景下提供高效的儲存和訪問效能。因此,混合索引成為了現代檔案系統設計的主流選擇。透過這種方式,檔案系統不僅能夠高效管理儲存空間,還能夠提供靈活的隨機訪問能力,以滿足不同使用者和應用程式的需求。