『壹』 八種數據結構特點
數據結構:計算機存儲、組織數據的方式。程序員的目標是為當前的問題選擇最優的數據結構。
八種數據結構:數組,棧,鏈表,隊列,堆,圖,樹,散列表,每種數據結構都有其特殊的存儲方式。
概念:
一維數組:數組元素+數組索引
多維數組:數組的元素也是數組
基本操作:insert,get,delete(刪除某個索引處的數組),size(獲取數組長度)
題目:
查找數組第二小的元素
查找第一個沒有重復的數組元素
合並2個排序號的數據
重新排列數組中的正數和負數
特點:棧是一種特殊的線性表,僅能在線性表的一端操作,棧頂允許操作,棧底不允許操作。 棧的特點是:先進後出,或者說是後進先出。棧中的元素採用LIFO (Last In First Out),即後進先出。
基本操作:Push(棧頂插入元素),Pop(返回棧最上方的元素,並刪除),isEmpty(查詢棧是否為空),Top(返回最上方元素,並不刪除)
題目:使用棧計算後綴表達式、使用棧為棧中的元素排序、檢查字元串中的括弧是否匹配正確
使用場景:棧常應用於實現遞歸功能方面的場景,例如斐波那契數列。撤回,即Ctrl+Z,是我們最常見的操作之一,大多數應用都會支持這個功能。你知道它是怎麼實現的嗎?答案是這樣的:把之前的應用狀態(限制個數)保存到內存中,最近的狀態放到第一個。這時,我們需要棧(stack)來實現這個功能。
概念:隊列(Queue)與棧類似,都是採用線性結構存儲數據。它們的區別在於,棧採用LIFO方式,而隊列採用先進先出,即FIFO(First in First Out)。
使用場景:因為隊列先進先出的特點拆閉,在多線程阻塞隊列管理中非常適用。
基本操作:Enqueue—在隊列末尾插入元素,Dequeue—將隊列第一個元素刪除i,sEmpty—查詢隊列是否為空,Top—返回隊列的第一個元素
習題:使用隊列實現棧,倒轉隊列的前K個元素,使用隊列將1到n轉換為二進制。
概念「鏈表(Linked List)也是線性結構,它與數組看起來非常像,但是它們的內存分配方式、內部結構和插入刪除操作方式都不一樣。鏈表是一系列節點組成的鏈,每一個節點保存了數據以及指向下一個節點的指針。鏈表頭指針指向第一個節點,如果鏈表為空,則頭指針為空或者為null。鏈表分為:單向鏈表,雙向鏈表。
使用場景:鏈表可以用來實現文件系統、哈正跡希表和鄰接表。
基本操作:InsertAtEnd—在鏈表結尾插入元素,InsertAtHead—在鏈表開頭插入元素,Delete—刪除鏈表的指定元素,DeleteAtHead—刪除鏈表第一個元素,Search—在鏈表中查詢指定元素,isEmpty—查詢鏈表是否為空
題目:倒轉1個鏈表,檢查鏈表中是否存在循環,返回鏈表倒數第N個元素,移除鏈表中的重復元素
概念:圖(graph)由多個節點(vertex)構成,節點之間闊以互相連接組成一個網路。(x, y)表示一條邊(edge),它表示節點x與y相連。邊可能會有權值(weight/cost)。
分類:無向圖,有向圖
表現形式:鄰接矩陣(Adjacency Matrix),鄰接表(Adjacency List)
遍歷圖的兩種演算法:廣度優先搜索(Breadth First Search),深度優先搜索(Depth First Search)
常見題目:
實現廣度優先搜索,實現深度優先搜索,檢查圖是否為樹,統計圖中邊的個數,使用Dijkstra演算法查找兩個節點之間的最短距離。
樹(Tree)是一個分層的數據結構,由節點和連接節點的邊組成。樹是一種特殊的圖,它與圖最大的區別是沒有循環。樹被廣泛應用在人工智慧和一些復雜演算法中,用來提供高效的存儲結構。
常見樹:N叉樹(N-ary Tree),平衡樹(Balanced Tree),二叉樹(Binary Tree),二叉查找樹(Binary Search Tree),平衡二叉舉御並樹(AVL Tree),紅黑樹(Red Black Tree),2-3樹(2–3 Tree)
題目:計算樹的高度,查找二叉平衡樹中第K大的元素,查找樹中與根節點距離為k的節點,查找二叉樹中某個節點所有祖先節點。
哈希(Hash)將某個對象變換為唯一標識符,該標識符通常用一個短的隨機字母和數字組成的字元串來代表。哈希可以用來實現各種數據結構,其中最常用的就是哈希表(hash table)。
哈希表通常由數組實現。
哈希表的性能取決於3個指標:
哈希函數哈希表的大小哈希沖突處理方式
題目:查找數組中對稱的組合,確認某個數組的元素是否為另一個數組元素的子集,確認給定的數組是否互斥。
前綴樹(Prefix Trees或者Trie) 與樹類似,用於處理字元串相關的問題時非常高效。它可以實現快速檢索,常用於字典中的單詞查詢,搜索引擎的自動補全甚至IP路由。
參考資料: http://www.cnblogs.com/williamjie/p/9558015.html
『貳』 基於flash存儲器的文件系統有哪些
Flash 存儲器( Flash Memory) 是一種高可靠性、高密度的固態存儲器件。 其存儲方式是完全非易失性的,掉電後可以保存數據;可以在線寫入,並可按頁連續位元組寫入,存取速度快,所以嵌入式系統通常使用Flash 存儲器作為存儲設備。 但Flash存儲器也存在著兩個主要缺陷:一是在重寫之前必須進行擦除,因為Flash 存儲器劃分成很多擦除塊(SectorOErase) ,對任何一位數據進行修改必須先擦除整個塊(Sector) ;二是擦除塊的擦除次數有限,當一個塊提前達到擦除次數上限時, 將導致整個Flash 存儲器無法使用。 所以,目前PC 機上很多成熟的基於磁碟的文件系統在Flash 存儲器上使用都存在著不足。
嵌入式系統應具有的特點: 一是高可靠性,在惡劣環境下系統仍能正常工作;二是低消耗,受成本限制系統設計必須量體裁衣,去除冗餘;三是高效率,在佔用較少資源情況下保證功能需求,這樣就要求演算法簡單,效率高。 而日誌文件系統(Log-St ruct ured File System) 在數據更新時無需將數據寫入原存儲區域,適應Flash 存儲器無法進行重寫這一特點。 目前,針對Flash 存儲器的缺陷而設計的linux 下的J FFS 文件系統,就是採用簡化的日誌文件系統。 J FFS 文件系統將磨損均衡集成於清除機制之中,在帶來掉電可恢復功能的同時,大大減少了塊擦除的次數,提高了文件系統的存取速度和效率。 但是,J FFS 文件系統無法單獨使用,或者使用於其它實時操作系統中。 對由於受成本和實時性限制而無法使用Linux 的一些嵌入式系統,也就無法使用J FFS 文件系統。基於上述分析,該嵌入式文件系統適合在開源實時操作系統(如μC/OS-II) 和無操作系統的情況下使用。
嵌入式文件系統原理
在日誌文件系統中,一個文件被修改後不是被寫入到原來的存儲空間,而是被加到所有內容的後面,象日誌一樣被更新,這就是日誌文件系統的基本原理。 由於同一個文件在文件系統中會留下不同的版本,所以系統需要設置一張表標注文件的最新與以前的版本。 在內容不斷添加時為不將存儲空間占滿,系統設計了一種回收機制,回收無效內容佔用的空間。
日誌文件系統在文件更新時不用將文件寫回原來的地址,這對Flash 存儲器這種存儲介質最為適合。 文中所設計的嵌入式文件系統採用了日誌文件系統的設計原理,以及J FFS 文件系統將磨損均衡集成於清除機制之中的方法。 該系統將一個可擦寫塊平分為多個簇,文件的讀寫以簇為單位進行。簇的狀態有3 種:臟、干凈和空。 臟表示所存內容已被置為無效;干凈表示所存數據有效;空表示可以寫入數據。 文件和目錄在該系統中被作為節點,一個節點佔用若干個簇,節點中的內容連續存儲,但不能越過塊邊界存儲。 該系統設置一個索引節點,保存整個系統的信息,其中包含保存有各簇狀態的簇狀態表。
每一次文件更新後內容都將被添加至末尾處,索引節點也被更新,總是佔用最末尾的干凈簇。 回收臟簇時,將所要擦除塊中的干凈簇重寫到空簇中,再進行塊擦除。 當內容寫至存儲體末端,則從頭部重新開始循環存儲。 所設計的文件系統的操作過程見圖1。
ic72新聞中心
嵌入式文件系統設計
Flash 存儲器中的存儲結構
Flash 存儲器中的存儲結構見圖2。 該存儲器中每個簇的第一個字作為簇的狀態字,表示此簇是否為一個節點的首簇或空簇。 每個節點的首部存放此節點屬性(文件/目錄/索引節點) 和節點標識號。
ic72新聞中心
索引節點
索引節點存放該文件系統的大部分信息。 包括32 位的索引節點更新號、一張簇狀態表、下一個要被擦除塊的塊號、給下一個新建節點(文件或目錄) 的節點編號、系統根目錄信息表。系統每一次更新都會產生新的索引節點,索引節點更新號加1。 按照Flash 存儲器的使用壽命10 年計算,需要每秒更新136 次以上,才能達到索引節點更新號的上限,所以認為擁有最大更新號的索引節點為最新的索引節點。 簇狀態表中對應每一個簇有兩個Bit 位,表示各個簇的狀態(干凈01 ,臟11 ,空00) 。 根目錄信息表存放根目錄下的各個目錄項,每個目錄項包括:屬性(文件0x1/目錄0x0) 、文件名或目錄名、節點編號、此文件(或目錄) 對應節點的起始簇地址、根目錄表的大小可變。
目錄節點
目錄節點存放的內容有目錄名,目錄項個數,及所有目錄項信息。 文件節點存放文件名,文件大小,文件屬性及文件內容,內存中的目錄結構見圖3。
ic72新聞中心
內存數據結構及基本操作
該文件系統載入(Mount ) 後,會在內存中建立一個系統的映象。 該映象包括:索引節點中的信息、目錄及文件信息、每個可擦寫塊中包含的節點信息、未存檔的節點信息。 簇狀態表、索引節點更新號、新節點編號、下一擦除塊號等索引節點中的內容,在內存中均作為不同的變數。 內存中為每個文件和目錄都建立了映象,數據結構見圖4 和圖5。
ic72新聞中心
ic72新聞中心
內存中的文件節點不包含文件真正的數據,而使用指針。 文件被打開時,在內存中創建一塊新存儲區域存放數據,數據指針便指向此存儲區,未被打開時,此指針指向空。 對於每個目錄有1 個目錄層數,表示此目錄的深度,如根目錄的目錄層數為0 ,根目錄的下一級目錄則為1 ,依此類推。 存儲地址保存文件或目錄在Flash 中的地址。 文件和目錄都被存在上一級目錄下,所屬目錄指針即指向上一級目錄在內存中的數據結構,根目錄的所屬目錄指針即為空。 對於同目錄下的不同節點,在內存中使用鏈表將其串聯,同目錄文件指針即聯成鏈表。 鏈表的首指針保存在上一級目錄中,首目錄項指針即指向鏈表的首項。 為提高塊擦寫的效率,存儲在同一個可擦寫塊中的各個節點在內存中也建立一個鏈表,塊隊列指針即用於連成此鏈表。 為標識被修改的節點,利用一個未保存隊列,未保存隊列指針即用來建立此隊列。
該文件系統載入(mount ) 時,首先順序掃描Flash 中的每個索引節點,查找出最大的索引節點更新號,此更新號對應的索引節點即為最新的索引節點。 查找到最新索引節點後,將簇狀態表等信息映射到內存的數據結構中。 依據索引節點中的根目錄信息,遍歷所有節點,建立內存中的目錄文件結構,並將節點添加到對應的擦寫塊隊列中。 對一個文件編輯並保存的過程見圖6。
ic72新聞中心
文件打開時,先在內存中分配一塊空間作為數據區,將內容寫入,並定位文件節點的數據指針指向該內存中的數據區。 如果文件內容被修改,就將文件節點添加到未存檔隊列,依次寫入Flash 存儲器中,並修改簇狀態表。 保存時將內存中數據區內容寫入Fhttp://www.xiupin365.net/sitemap.html?lash 中,釋放申請的內存空間,修改節點中的數據指針和簇狀態表,再將文件的所有上級目錄重新寫入Flash ,最後將更新後的索引節點內容寫入Flash。 如果文件未被修改,則只需修改數據指針即可。
節點加入未存檔隊列的順序按照目錄層數的大小排列,文件節點排在隊列首,目錄層數最大的排在其後,目錄層數為1 的排在隊列末尾,根目錄不加入未存檔隊列。
嵌入式文件系統特殊處理機制
均衡擦寫機制
為了避免任意一個可擦除塊因擦寫次數過多而過早報廢,文件系統對Flash擦寫時採用了均衡擦寫機制。 考慮到系統的精簡性,擦寫在整片Flash 的各塊中依次進行,一塊擦寫完後,下一個被擦寫的塊即為後一個塊,在系統的索引節點中保存了下一個要擦除的塊號。 當文件系統中的剩餘空間減少到設定值時,系統會擦除此塊,以回收臟簇佔用的空間。 對應每個可擦寫塊都有一個節點隊列,此塊中包含的節點都加入其中。塊擦除的流程見圖7。
ic72新聞中心
首先,將未保存於隊列中的節點保存,清未保存隊列。 然後將塊隊列中的所有文件節點轉移到空簇中,同時將文件路徑上的各級目錄加入到未存檔隊列中。 對於塊隊列中的目錄節點,則將它和其路徑上的各級目錄加入未存檔隊列中,按照未保存隊列的順序,依次將各個目錄寫入Flash 中,最後寫入最新的索引節點。 因為目錄節點加入未存檔隊列時,按照目錄層數的大小排列,所以按照未保存隊列的順序寫入時,可以保證當一個目錄要被寫入Flash 時,它的所有下級目錄已被寫入Flash 中。 所有下級目錄在Flash 中的存儲地址都已確定。當該文件系統的空間將達到存儲上限時,可能會出現特殊情況,即廢簇回收時,空簇的空間不足,無法將所有干凈簇重寫。 文件系統為此建立了應急機制,先將文件節點內容存在內存中,這時新建一個臨時未保存隊列,專門保存文件節點,在塊擦寫完成後,將剩餘的文件節點寫入新的空簇中,其演算法與圖7 所示流程大致相同。 但是,一旦在擦寫時斷電,會導致該塊上的所有數據丟失。
斷電錯誤處理機制
當系統遭遇斷電重新啟動後,索引節點中的信息會與系統中的狀態不符,這時便需要錯誤處理機制。 錯誤一般是索引節點中標注的空簇已被寫入了數據,錯誤處理就是將此簇標志為臟簇,並查找下一個空簇重新寫入。
多任務處理機制
該文件系統允許同時打開多個文件,在多任務操作系統下,為了避免沖突建立了多任務處理機制。 系統允許打開的多個文件在內存中同時被編輯修改,但是對Flash 寫入操作有限制。 處理方法是設立Flash 寫入保護區,在此區中只允許當前正在執行的任務執行Flash 寫入操作。 實現Flash 寫入保護區的方法是建立一個初始值為1 的信號量,當一個節點需要Flash 寫入時,首先申請信號量,完成後再釋放信號量。 Flash 寫入保護區見圖6 、圖7。在圖6 中,空操作語句是用來對多個文件的保存進行同步。 例如,有文件1 和文件2 需要保存,先將文件1 的內容寫入Flash 中,文件1 路徑下的目錄節點被添加到未保存隊列中,再將文件2 的內容寫入Flash 中,文件2 路徑下的目錄節點也被添加到未保存隊列中,最後將未保存隊列中的所有節點都寫入Flash 中。 這樣,如果同一路徑下的兩個文件同時存檔,可避免路徑下的相同目錄節點被寫入兩次,從而提高了效率。 不足之處在於,如果很多文件同時存檔,會導致索引節點在一段時間內都無法寫入Flash 存儲器,有斷電丟失的危險。 但對於一般嵌入式系統來說,很少會碰到這種情況。 當進行Flash存儲器擦寫時,在取塊隊列首節點至索引節點寫入完成這段時間內都不允許進行其他Flash 存儲器的寫入操作,這是為了保證數據的完整性,同時也提高了文件系統的穩定性。
無目錄文件系統的優化
許多嵌入式系統設計中雖沒有目錄管理的要求,但是對執行效率和資源消耗的要求較高。 對於不要求有目錄管理的精簡文件系統,在設計時也進行了優化。 精簡文件系統在Flash 中的存儲格式與上述設計相同,文件系統中的所有文件信息都保存在索引節點的根目錄信息表中。 精簡文件系統在內存中的映象則要簡單很多,只包含索引節點中的信息,包括簇狀態表、下一個擦除塊、下一個新節點的標號和根目錄信息,而不用為每個文件都建立內存中的映象,節省大量的內存空間。 文件的編輯存檔過程簡化為:打開文件、編輯、將文件寫入Flash 存儲器、將修改後的索引節點寫入Flash 存儲器。 擦寫則只需通過查詢根目錄信息表中的各個目錄項,將塊中的所有文件節點寫入空簇即可。在無目錄管理的情況下,精簡文件系統佔用的內存資源可以減少,操作也可便捷,提高了效率。 對於大量只需要按名存取的簡單文件管理的小型嵌入式系統而言,針對Flash 存儲器的簡單文件系統將佔用資源少,執行效率高,有很大的應用價值。
嵌入式文件系統實現及性能分析
該文件系統的實現採用了分層方法,分為3 層4 個部分:應用程序介面、文件系統核心、操作系統調用介面、Flash 存儲器驅動,實現結構見圖8。
ic72新聞中心
實現平台中RTOS 為μC/OSOII 實時操作系統,CPU 使用三星S4510B作為處理器,Flash 存儲器晶元為FUJ ITSU 的29LV160 TE。 針對不同的實時操作系統和Flash 存儲器晶元需要實現不同的操作系統介面和Flash 存儲器驅動。
針對μC/ OSOII 編寫操作系統調用介面,包括5個函數: ①系統調用介面初始化FS_Sys_Interface_Init ( ) ,創建互斥信號量和內存分區; ② Flash 寫入關閉FS_Sys_Write_Lock ( ) ,禁止Flash 寫入操作,調用μC/OS-II 中OSMutePend ( ) ; ③ Flash寫入打開FS_Sys_Write_Unlock ( ) ,重新允許Flash 寫入操作,調用μC/OS-II 中OSMutePost() ; ④內存空間申請FS_Sys_Mem_Alloc( ) 和內存空間添加FS_Sys_Mem_Add ( ) , 都調用OSMemGet ( ) 來完成; ⑤內存空間釋放FS_Sys_Mem_Free ( ) ,調用OSMemPut ( ) 完成,將申請的內存塊全部釋放。針對29LV160 TE 這款Flash 存儲器晶元,定義一個FlashDef 結構體的全局變數, 用於存儲Flash 器件信息,並且編寫針對此款Flash 的塊擦寫函數FS_Device_Sector_Erase ( ) 和數據寫入函數FJ FS_Device_Write ( ) 。
完成這兩部分的實現後,該系統就可運行調試。 測試應用程序介面(API) 。 應該提供的各部分功能,並在突然斷電情況下,測試文件系統的恢復情況。無目錄管理的精簡文件系統的載入,可在2μs內完成,文件寫入耗時主要為快閃記憶體的等待時間,系統本身只佔用不到200 個位元組的內存,產生的代碼段大小為7 K。 完整的文件系統載入時,需要建立內存中映象,耗時根據文件數量的多少而不同,一般為10μs ,產生的代碼段大小為11 K。 系統寫入效率較高,在無目錄管理的配置下尤其明顯。 試驗中系統在多次斷電的情況下,系統仍能恢復至上次存檔的狀態,雖會導致個別文件未更新,但不會導致文件系統崩潰。
『叄』 不同操作系統支持不同的文件系統,誰能幫我介紹一下不同文件系統有何區別,
文件系統就是建立在存儲器件(如硬碟)對物理存儲介質的讀寫之上的。文件系統不關心存儲介質的絕對物理位置。
簡單說下FAT吧 相信你把州友這個弄明白了 其他的就簡單多了。
首先,文逗悶件系統的建立是為了使文件管理和調用、存儲介質管理等事務的效率提高。不管什麼文件系統讀取文件都得從某一地址讀出。
拿硬碟來說吧。你先去弄明白幾個概念。扇區、磁頭和柱面。
fat就是把一系列連續的存儲區域(扇區)劃分為幾個邏輯盤。每個邏輯盤有分區DBR,FAT,FDT,數據區等等,中間還有一些做其他用途的存儲空間。
物理第一扇區有MBR表(主引導記錄)和分區表DPT。這兩個表是系統啟動有關的。所謂表,也就是按規定順序放置的一系列信息。此扇區是操作系統不可存取的。分區表記錄了硬碟分區的信息、系統安裝盤的信息等等。通過BPB可以找到安裝系統的盤(叫做活動分區,在BPB表中有相關描述)的信息,然後到那個分區讀取第一個扇區,即含DBR表(dos引導記錄)的扇區。然後查找系統文件,開始載入系統。
DBR後有FAT,即文件分配表。系統把數據區分為簇來管理。每個簇對應一個FAT表項。把表項編號帶入計算式既可以得到扇區號。
FDT,即根目錄表,這個表由多個FDT項構成。每個項有文件的相關信息。如文件名、擴展名、創建日期、起始簇號等。如果文件比較小,放在一個簇里,通過起始簇號,計算出文件的內容的冊指槐扇區號,然後就可以讀出來。有的文件由多個簇存放。則對應的FAT中存放的下一個簇的簇號,類似與鏈表的機制。
其實要深究起來的話。內容可多了去了。有不明白的可以跟我留言交流。
『肆』 程序員必備知識(操作系統5-文件系統)
本篇與之前的第三篇的內存管理知識點有相似的地方
對於運行的進程來說,內存就像一個紙箱子, 僅僅是一個暫存數據的地方, 而且空間有限。如果我們想要進程結束之後,數據依然能夠保存下來,就不能只保存在內存里,而是應該保存在 外部存儲 中。就像圖書館這種地方,不僅空間大,而且能夠永久保存。
我們最常用的外部存儲就是 硬碟 ,數據是以文件的形式保存在硬碟上的。為了管理這些文件,我們在規劃文件系統的時候,需要考慮到以下幾點。
第一點,文件系統要有嚴格的組織形式,使得文件能夠 以塊為單位進行存儲 。這就像圖書館里,我們會給設置一排排書架,然後再把書架分成一個個小格子,有的項目存放的資料非常多,一個格子放不下,就需要多個格子來進行存放。我們把這個區域稱為存放原始資料的 倉庫區 。
第二點,文件系統中也要有 索引區 ,用來方便查找一個文件分成的多個塊都存放在了什麼位置。這就好比,圖書館的書太多了,為了方便查找,我們需要專門設置一排書架,這裡面會寫清楚整個檔案庫有哪些資料,資料在哪個架子的哪個格子上。這樣找資料的時候就不用跑遍整個檔案庫,在這個書架上找到後,直奔目標書架就可以了。
第三點,如果文件系統中有的文件是熱點文件,近期經常被讀取和寫入,文件系統應該有 緩存層 。這就相當於圖書館裡面的熱門圖書區,這裡面的書都是暢銷書或者是常常被借還的圖書。因為借還的次數比較多,那就沒必要每次有人還了之後,還放回遙遠的貨架,我們可以專門開辟一個區域, 放置這些借還頻次高的圖書。這樣借還的效率就會提高。
第四點,文件應該用 文件夾 的形式組織起來,方便管理和查詢。這就像在圖書館裡面,你可以給這些資料分門別類,比如分成計算機類.文學類.歷史類等等。這樣你也容易管理,項目組借閱的時候只要在某個類別中去找就可以了。
在文件系統中,每個文件都有一個名字,這樣我們訪問一個文件,希望通過它的名字就可以找到。文件名就是一個普通的文本。 當然文件名會經常沖突,不同用戶取相同的名字的情況還是會經常出現的。
要想把很多的文件有序地組織起來,我們就需要把它們成為 目錄 或者文件夾。這樣,一個文件夾里可以包含文件夾,也可以包含文件,這樣就形成了一種 樹形結構 。而我們可以將不同的用戶放在不同的用戶目錄下,就可以一定程度上避免了命名的沖突問題。
第五點,Linux 內核要在自己的內存裡面維護一套數據結構,來保存哪些文件被哪些進程打開和使用 。這就好比,圖書館里會有個圖書管理系統,記錄哪些書被借閱了,被誰借閱了,借閱了多久,什麼時候歸還。
文件系統是操作系統中負責管理持久數據的子系統,說簡單點,就是負責把用戶的文件存到磁碟硬體中,因為即使計算機斷電了,磁碟里的數據並不會丟失,所以可以持久化的保存文件。
文件系統的基本數據單位是 文件 ,它的目的是對磁碟上的文件進行組織管理,那組織的方式不同,就會形成不同的文件系統。
Linux最經典的一句話是:「一切皆文件」,不僅普通的文件和目錄,就連塊設備、管道、socket 等,也都是統一交給文件系統管理的。
Linux文件系統會為每個文件分配兩個數據結構: 索引節點(index node) 和 目錄項(directory entry) ,它們主要用來記錄文件的元信息和目錄層次結構。
●索引節點,也就是inode, 用來記錄文件的元信息,比如inode編號、文件大小訪問許可權、創建時間、修改時間、 數據在磁碟的位置 等等。 索引節點是文件的唯一標識 ,它們之間一一對應, 也同樣都會被 存儲在硬碟 中,所以索引節點同樣佔用磁碟空間。
●目錄項,也就是dentry, 用來記錄文件的名字、索引節點指針以及與其他目錄項的層級關聯關系。多個目錄項關聯起來,就會形成 目錄結構 ,但它與索引節點不同的是,目錄項是由內核維護的一個數據結構,不存放於磁碟,而是 緩存在內存 。
由於索引節點唯一標識一個文件,而目錄項記錄著文件的名,所以目錄項和索引節點的關系是多對一,也就是說,一個文件可以有多個別字。比如,硬鏈接的實現就是多個目錄項中的索引節點指向同一個文件。
注意,目錄也是文件,也是用索引節點唯一標識,和普通文件不同的是,普通文件在磁碟裡面保存的是文件數據,而目錄文件在磁碟裡面保存子目錄或文件。
(PS:目錄項和目錄不是一個東西!你也不是一個東西(^_=), 雖然名字很相近,但目錄是個文件。持久化存儲在磁碟,而目錄項是內核一個數據結構,緩存在內存。
如果查詢目錄頻繁從磁碟讀,效率會很低,所以內核會把已經讀過的目錄用目錄項這個數據結構緩存在內存,下次再次讀到相同的目錄時,只需從內存讀就可以,大大提高了 文件系統的效率。
目錄項這個數據結構不只是表示目錄,也是可以表示文件的。)
磁碟讀寫的最小單位是 扇區 ,扇區的大小隻有512B大小,很明顯,如果每次讀寫都以這么小為單位,那這讀寫的效率會非常低。
所以,文件系統把多個扇區組成了一個 邏輯塊 ,每次讀寫的最小單位就是邏輯塊(數據塊) , Linux中的邏輯塊大小為4KB,也就是一次性讀寫 8個扇區,這將大大提高了磁碟的讀寫的效率。
以上就是索引節點、目錄項以及文件數據的關系,下面這個圖就很好的展示了它們之間的關系:
索引節點是存儲在硬碟上的數據,那麼為了加速文件的訪問,通常會把索引節點載入到內存中。
另外,磁碟進行格式化的時候,會被分成三個存儲區域,分別是超級塊、索引節點區和數據塊區。
●超級塊,用來存儲文件系統的詳細信息,比如塊個數、塊大小、空閑塊等等。
●索引節點區,用來存儲索引節點;
●數據塊區,用來存儲文件或目錄數據;
我們不可能把超級塊和索引節點區全部載入到內存,這樣內存肯定撐不住,所以只有當需要使用的時候,才將其載入進內存,它們載入進內存的時機是不同的.
●超級塊:當文件系統掛載時進入內存;
●索引節點區:當文件被訪問時進入內存;
文件系統的種類眾多,而操作系統希望 對用戶提供一個統一的介面 ,於是在用戶層與文件系統層引入了中間層,這個中間層就稱為 虛擬文件系統(Virtual File System, VFS) 。
VFS定義了一組所有文件系統都支持的數據結構和標准介面,這樣程序員不需要了解文件系統的工作原理,只需要了解VFS提供的統一介面即可。
在Linux文件系統中,用戶空間、系統調用、虛擬機文件系統、緩存、文件系統以及存儲之間的關系如下圖:
Linux支持的文件系統也不少,根據存儲位置的不同,可以把文件系統分為三類:
●磁碟的文件系統,它是直接把數據存儲在磁碟中,比如Ext 2/3/4. XFS 等都是這類文件系統。
●內存的文件系統,這類文件系統的數據不是存儲在硬碟的,而是佔用內存空間,我們經常用到的/proc 和/sys文件系統都屬於這一類,讀寫這類文件,實際上是讀寫內核中相關的數據。
●網路的文件系統,用來訪問其他計算機主機數據的文件系統,比如NFS. SMB等等。
文件系統首先要先掛載到某個目錄才可以正常使用,比如Linux系統在啟動時,會把文件系統掛載到根目錄。
在操作系統的輔助之下,磁碟中的數據在計算機中都會呈現為易讀的形式,並且我們不需要關心數據到底是如何存放在磁碟中,存放在磁碟的哪個地方等等問題,這些全部都是由操作系統完成的。
那麼,文件數據在磁碟中究竟是怎麼樣的呢?我們來一探究竟!
磁碟中的存儲單元會被劃分為一個個的「 塊 」,也被稱為 扇區 ,扇區的大小一般都為512byte.這說明即使一塊數據不足512byte,那麼它也要佔用512byte的磁碟空間。
而幾乎所有的文件系統都會把文件分割成固定大小的塊來存儲,通常一個塊的大小為4K。如果磁碟中的扇區為512byte,而文件系統的塊大小為4K,那麼文件系統的存儲單元就為8個扇區。這也是前面提到的一個問題,文件大小和佔用空間之間有什麼區別?文件大小是文件實際的大小,而佔用空間則是因為即使它的實際大小沒有達到那麼大,但是這部分空間實際也被佔用,其他文件數據無法使用這部分的空間。所以我們 寫入1byte的數據到文本中,但是它佔用的空間也會是4K。
這里要注意在Windows下的NTFS文件系統中,如果一開始文件數據小於 1K,那麼則不會分配磁碟塊來存儲,而是存在一個文件表中。但是一旦文件數據大於1K,那麼不管以後文件的大小,都會分配以4K為單位的磁碟空間來存儲。
與內存管理一樣,為了方便對磁碟的管理,文件的邏輯地址也被分為一個個的文件塊。於是文件的邏輯地址就是(邏輯塊號,塊內地址)。用戶通過邏輯地址來操作文件,操作系統負責完成邏輯地址與物理地址的映射。
不同的文件系統為文件分配磁碟空間會有不同的方式,這些方式各自都有優缺點。
連續分配要求每個文件在磁碟上有一組連續的塊,該分配方式較為簡單。
通過上圖可以看到,文件的邏輯塊號的順序是與物理塊號相同的,這樣就可以實現隨機存取了,只要知道了第一個邏輯塊的物理地址, 那麼就可以快速訪問到其他邏輯塊的物理地址。那麼操作系統如何完成邏輯塊與物理塊之間的映射呢?實際上,文件都是存放在目錄下的,而目錄是一種有結構文件, 所以在文件目錄的記錄中會存放目錄下所有文件的信息,每一個文件或者目錄都是一個記錄。 而這些信息就包括文件的起始塊號和佔有塊號的數量。
那麼操作系統如何完成邏輯塊與物理塊之間的映射呢? (邏輯塊號, 塊內地址) -> (物理塊號, 塊內地址),只需要知道邏輯塊號對應的物理塊號即可,塊內地址不變。
用戶訪問一個文件的內容,操作系統通過文件的標識符找到目錄項FCB, 物理塊號=起始塊號+邏輯塊號。 當然,還需要檢查邏輯塊號是否合法,是否超過長度等。因為可以根據邏輯塊號直接算出物理塊號,所以連續分配支持 順序訪問和隨機訪問 。
因為讀/寫文件是需要移動磁頭的,如果訪問兩個相隔很遠的磁碟塊,移動磁頭的時間就會變長。使用連續分配來作為文件的分配方式,會使文件的磁碟塊相鄰,所以文件的讀/寫速度最快。
連續空間存放的方式雖然讀寫效率高,但是有 磁碟空間碎片 和 文件長度不易擴展 的缺陷。
如下圖,如果文件B被刪除,磁碟上就留下一塊空缺,這時,如果新來的文件小於其中的一個空缺,我們就可以將其放在相應空缺里。但如果該文件的大小大於所
有的空缺,但卻小於空缺大小之和,則雖然磁碟上有足夠的空缺,但該文件還是不能存放。當然了,我們可以通過將現有文件進行挪動來騰出空間以容納新的文件,但是這個在磁碟挪動文件是非常耗時,所以這種方式不太現實。
另外一個缺陷是文件長度擴展不方便,例如上圖中的文件A要想擴大一下,需要更多的磁碟空間,唯一的辦法就只能是挪動的方式,前面也說了,這種方式效率是非常低的。
那麼有沒有更好的方式來解決上面的問題呢?答案當然有,既然連續空間存放的方式不太行,那麼我們就改變存放的方式,使用非連續空間存放方式來解決這些缺陷。
非連續空間存放方式分為 鏈表方式 和 索引方式 。
鏈式分配採取離散分配的方式,可以為文件分配離散的磁碟塊。它有兩種分配方式:顯示鏈接和隱式鏈接。
隱式鏈接是只目錄項中只會記錄文件所佔磁碟塊中的第一塊的地址和最後一塊磁碟塊的地址, 然後通過在每一個磁碟塊中存放一個指向下一 磁碟塊的指針, 從而可以根據指針找到下一塊磁碟塊。如果需要分配新的磁碟塊,則使用最後一塊磁碟塊中的指針指向新的磁碟塊,然後修改新的磁碟塊為最後的磁碟塊。
我們來思考一個問題, 採用隱式鏈接如何將實現邏輯塊號轉換為物理塊號呢?
用戶給出需要訪問的邏輯塊號i,操作系統需要找到所需訪問文件的目錄項FCB.從目錄項中可以知道文件的起始塊號,然後將邏輯塊號0的數據讀入內存,由此知道1號邏輯塊的物理塊號,然後再讀入1號邏輯塊的數據進內存,此次類推,最終可以找到用戶所需訪問的邏輯塊號i。訪問邏輯塊號i,總共需要i+ 1次磁碟1/0操作。
得出結論: 隱式鏈接分配只能順序訪問,不支持隨機訪問,查找效率低 。
我們來思考另外一個問題,採用隱式鏈接是否方便文件拓展?
我們知道目錄項中存有結束塊號的物理地址,所以我們如果要拓展文件,只需要將新分配的磁碟塊掛載到結束塊號的後面即可,修改結束塊號的指針指向新分配的磁碟塊,然後修改目錄項。
得出結論: 隱式鏈接分配很方便文件拓展。所有空閑磁碟塊都可以被利用到,無碎片問題,存儲利用率高。
顯示鏈接是把用於鏈接各個物理塊的指針顯式地存放在一張表中,該表稱為文件分配表(FAT, File Allocation Table)。
由於查找記錄的過程是在內存中進行的,因而不僅顯著地 提高了檢索速度 ,而且 大大減少了訪問磁碟的次數 。但也正是整個表都存放在內存中的關系,它的主要的缺點是 不適 用於大磁碟 。
比如,對於200GB的磁碟和1KB大小的塊,這張表需要有2億項,每一項對應於這2億個磁碟塊中的一個塊,每項如果需要4個位元組,那這張表要佔用800MB內存,很顯然FAT方案對於大磁碟而言不太合適。
一直都在,加油!(*゜Д゜)σ凸←自爆按鈕
鏈表的方式解決了連續分配的磁碟碎片和文件動態打展的問題,但是不能有效支持直接訪問(FAT除外) ,索引的方式可以解決這個問題。
索引的實現是為每個文件創建一個 索引數據塊 ,裡面存放的 是指向文件數據塊的指針列表 ,說白了就像書的目錄一樣,要找哪個章節的內容,看目錄查就可以。
另外, 文件頭需要包含指向索引數據塊的指針 ,這樣就可以通過文件頭知道索引數據塊的位置,再通過索弓|數據塊里的索引信息找到對應的數據塊。
創建文件時,索引塊的所有指針都設為空。當首次寫入第i塊時,先從空閑空間中取得一個塊, 再將其地址寫到索引塊的第i個條目。
索引的方式優點在於:
●文件的創建、增大、縮小很方便;
●不會有碎片的問題;
●支持順序讀寫和隨機讀寫;
由於索引數據也是存放在磁碟塊的,如果文件很小,明明只需一塊就可以存放的下,但還是需要額外分配一塊來存放索引數據,所以缺陷之一就是存儲索引帶來的開銷。
如果文件很大,大到一個索引數據塊放不下索引信息,這時又要如何處理大文件的存放呢?我們可以通過組合的方式,來處理大文件的存儲。
先來看看 鏈表+索引 的組合,這種組合稱為 鏈式索引塊 ,它的實現方式是在 索引數據塊留出一個存放下一個索引數據塊的指針 ,於是當一個索引數據塊的索引信息用完了,就可以通過指針的方式,找到下一個索引數據塊的信息。那這種方式也會出現前面提到的鏈表方式的問題,萬一某個指針損壞了,後面的數據也就會無法讀取了。
還有另外一種組合方式是 索引+索引 的方式,這種組合稱為多級索引塊,實現方式是通過一個索引塊來存放多個索引數據塊,一層套一層索引, 像極了俄羅斯套娃是吧๑乛◡乛๑
前面說到的文件的存儲是針對已經被佔用的數據塊組織和管理,接下來的問題是,如果我要保存一個數據塊, 我應該放在硬碟上的哪個位置呢?難道需要將所有的塊掃描一遍,找個空的地方隨便放嗎?
那這種方式效率就太低了,所以針對磁碟的空閑空間也是要引入管理的機制,接下來介紹幾種常見的方法:
●空閑表法
●空閑鏈表法
●點陣圖法
空閑表法
空閑表法就是為所有空閑空間建立一張表,表內容包括空閑區的第一個塊號和該空閑區的塊個數,注意,這個方式是連續分配的。如下圖:
當請求分配磁碟空間時,系統依次掃描空閑表裡的內容,直到找到一個合適的空閑區域為止。當用戶撤銷一個文件時,系統回收文件空間。這時,也需順序掃描空閑表,尋找一個空閑表條目並將釋放空間的第一個物理塊號及它佔用的塊數填到這個條目中。
這種方法僅當有少量的空閑區時才有較好的效果。因為,如果存儲空間中有著大量的小的空閑區,則空閑表變得很大,這樣查詢效率會很低。另外,這種分配技術適用於建立連續文件。
空閑鏈表法
我們也可以使用鏈表的方式來管理空閑空間,每一個空閑塊里有一個指針指向下一個空閑塊,這樣也能很方便的找到空閑塊並管理起來。如下圖:
當創建文件需要一塊或幾塊時,就從鏈頭上依次取下一塊或幾塊。反之,當回收空間時,把這些空閑塊依次接到鏈頭上。
這種技術只要在主存中保存一個指針, 令它指向第一個空閑塊。其特點是簡單,但不能隨機訪問,工作效率低,因為每當在鏈上增加或移動空閑塊時需要做很多1/0操作,同時數據塊的指針消耗了一定的存儲空間。
空閑表法和空閑鏈表法都不適合用於大型文件系統,因為這會使空閑表或空閑鏈表太大。
點陣圖法
點陣圖是利用二進制的一位來表示磁碟中一個盤塊的使用情況,磁碟上所有的盤塊都有一個二進制位與之對應。
當值為0時,表示對應的盤塊空閑,值為1時,表示對應的盤塊已分配。它形式如下:
在Linux文件系統就採用了點陣圖的方式來管理空閑空間,不僅用於數據空閑塊的管理,還用於inode空閑塊的管理,因為inode也是存儲在磁碟的,自然也要有對其管理。
前面提到Linux是用點陣圖的方式管理空閑空間,用戶在創建一個新文件時, Linux 內核會通過inode的點陣圖找到空閑可用的inode,並進行分配。要存儲數據時,會通過塊的點陣圖找到空閑的塊,並分配,但仔細計算一下還是有問題的。
數據塊的點陣圖是放在磁碟塊里的,假設是放在一個塊里,一個塊4K,每位表示一個數據塊,共可以表示4 * 1024 * 8 = 2^15個空閑塊,由於1個數據塊是4K大小,那麼最大可以表示的空間為2^15 * 4 * 1024 = 2^27個byte,也就是128M。
也就是說按照上面的結構,如果採用(一個塊的點陣圖+ 一系列的塊),外加一(個塊的inode的點陣圖+一系列的inode)的結構能表示的最大空間也就128M,
這太少了,現在很多文件都比這個大。
在Linux文件系統,把這個結構稱為一個 塊組 ,那麼有N多的塊組,就能夠表示N大的文件。
最終,整個文件系統格式就是下面這個樣子。
最前面的第一個塊是引導塊,在系統啟動時用於啟用引導,接著後面就是一個一個連續的塊組了,塊組的內容如下:
● 超級塊 ,包含的是文件系統的重要信息,比如inode總個數、塊總個數、每個塊組的inode個數、每個塊組的塊個數等等。
● 塊組描述符 ,包含文件系統中各個塊組的狀態,比如塊組中空閑塊和inode的數目等,每個塊組都包含了文件系統中「所有塊組的組描述符信息」。
● 數據點陣圖和inode點陣圖 ,用於表示對應的數據塊或inode是空閑的,還是被使用中。
● inode 列表 ,包含了塊組中所有的inode, inode 用於保存文件系統中與各個文件和目錄相關的所有元數據。
● 數據塊 ,包含文件的有用數據。
你可以會發現每個塊組里有很多重復的信息,比如 超級塊和塊組描述符表,這兩個都是全局信息,而且非常的重要 ,這么做是有兩個原因:
●如果系統崩潰破壞了超級塊或塊組描述符,有關文件系統結構和內容的所有信息都會丟失。如果有冗餘的副本,該信息是可能恢復的。
●通過使文件和管理數據盡可能接近,減少了磁頭尋道和旋轉,這可以提高文件系統的性能。
不過,Ext2 的後續版本採用了稀疏技術。該做法是,超級塊和塊組描述符表不再存儲到文件系統的每個塊組中,而是只寫入到塊組0、塊組1和其他ID可以表示為3、5、7的冪的塊組中。
在前面,我們知道了一個普通文件是如何存儲的,但還有一個特殊的文件,經常用到的目錄,它是如何保存的呢?
基於Linux 一切切皆文件的設計思想,目錄其實也是個文件,你甚至可以通過vim打開它,它也有inode, inode 裡面也是指向一些塊。
和普通文件不同的是, 普通文件的塊裡面保存的是文件數據,而目錄文件的塊裡面保存的是目錄裡面一項一項的文件信息 。
在目錄文件的塊中,最簡單的保存格式就是 列表 ,就是一項一項地將目錄下的文件信息(如文件名、文件inode.文件類型等)列在表裡。
列表中每一項就代表該目錄下的文件的文件名和對應的inode,通過這個inode,就可以找到真正的文件。
通常,第一項是「則」,表示當前目錄,第二項是.,表示上一級目錄, 接下來就是一項一項的文件名和inode。
如果一個目錄有超級多的文件,我們要想在這個目錄下找文件,按照列表一項一項的找,效率就不高了。
於是,保存目錄的格式改成 哈希表 ,對文件名進行哈希計算,把哈希值保存起來,如果我們要查找一個目錄下面的文件名,可以通過名稱取哈希。如果哈希能夠匹配上,就說明這個文件的信息在相應的塊裡面。
Linux系統的ext文件系統就是採用了哈希表,來保存目錄的內容,這種方法的優點是查找非常迅速,插入和刪除也較簡單,不過需要一些預備措施來避免哈希沖突。
目錄查詢是通過在磁碟上反復搜索完成,需要不斷地進行/0操作,開銷較大。所以,為了減少/0操作,把當前使用的文件目錄緩存在內存,以後要使用該文件時只要在內存中操作,從而降低了磁碟操作次數,提高了文件系統的訪問速度。
感謝您的閱讀,希望您能攝取到知識!加油!沖沖沖!(發現光,追隨光,成為光,散發光!)我是程序員耶耶!有緣再見。<-biubiu-⊂(`ω´∩)
『伍』 請問 電腦向移動硬碟考大量電影時(上百G),為什麼復制再刪除 要比 剪切速度快很多
因碰讓為剪切是復制的時候同時在刪納孫除,兩種同時進行當然慢了
這和電腦有關,受硬碟讀取寫入的速率影響,如果你的硬碟速率高的話笑茄局就不會有太大差別了
『陸』 jffs2的詳述
節點頭部定義和兼容性
JFFS2 將文件系統的數據和原數據以節點的形式存儲在快閃記憶體上,具體來說節點頭部的定義如下:
圖跡纖一
幻數屏蔽位:0x1985 用來標識 JFFS2 文件系統。
節點類型:JFFS2 自身定義了三種節點類型,但是考慮到文件系統可擴展性和兼容性,JFFS2從 ext2 借鑒了經驗,節點類型的最高兩位被用來定義節點的兼容屬性,具體來說有下面幾種兼容屬性:
JFFS2_FEATURE_INCOMPAT:當 JFFS2 發現了一個不能識別的節點類型,並且它的兼容屬性是 JFFS2_FEATURE_INCOMPAT,那麼 JFFS2 必須拒絕掛載(mount)文件系統。
JFFS2_FEATURE_ROCOMPAT:當 JFFS2 發現了一個不能識別的節點類型,並且它的兼容屬性是 JFFS2_FEATURE_ROCOMPAT,那麼 JFFS2 必須以只讀的方式掛載文件系統。
JFFS2_FEATURE_RWCOMPAT_DELETE:當 JFFS2 發現了一個不能識別的節點類型,並且它的兼容屬性是 JFFS2_FEATURE_RWCOMPAT_DELETE,那麼在垃圾回收的時候,這個節點可以被刪除。
JFFS2_FEATURE_RWCOMPAT_COPY:當 JFFS2 發現了一個不能識別的節點類型,並且它的兼容屬性是 JFFS2_FEATURE_RWCOMPAT_COPY,那麼在垃圾回收的時候,這個節點要被拷貝到新的位置。
節點總長度:包括節點頭和數據的長度。
節點頭部 CRC 校驗:包含節點頭部的校驗碼歲鍵,為文件系統的可靠性提供了支持。
節點類型
JFFS2 定義了三種節點類型:
JFFS2_NODETYPE_INODE: INODE 節點包含了i-節點的原數據(i節點號,文件的組 ID, 屬主 id, 訪問時間,偏移,長度等),文件數據被附在 INODE 節點之後。除此之外,每個 INODE 節點還有一個版本號,它被用來維護屬於一個i-節點的所有 INODE 節點的全序關系。下面舉例來說明這個全序關系在 JFFS2 的使用:
圖二
因此,當文件系統從快閃記憶體上讀節點信息後,會生成下面的映射信息:
圖三
根據這個映射信息表,文件系統就知道到相應的 INODE 節點去讀取相應的文件內容。 最後要說明的是,JFFS2 支持文件數據的壓縮存儲,因此在 INODE 節點中還包含了所使用的壓縮演算法,在讀取數據的時候選擇相應的壓縮演算法來解壓縮。
JFFS2_NODETYPE_DIRENT:DIRENT 節點就是把文件名與 i 節點對應起來。在 DIRENT節點中也有一個版本號,這個版本號的作用主要是用來刪除一個dentry。具體來說,當我們要乎州巧從一個目錄中刪除一個dentry時,我們要寫一個 DIRENT 節點,節點中的文件名與被刪除的 dentry 中的文件名相同,i 節點號置為 0,同時設置一個更高的版本號。
JFFS2_NODETYPE_CLEANMARKER:當一個擦寫塊被擦寫完畢後,CLEANMARKER 節點會被寫在 NOR flash 的開頭,或 NAND flash 的 OOB(Out-Of-Band) 區域來表明這是一個干凈,可寫的擦寫塊。在 JFFS v1 中,如果掃描到開頭的 1K 都是 0xFF 就認為這個擦寫塊是干凈的。但是在實際的測試中發現,如果在擦寫的過程中突然掉電,擦寫塊上也可能會有大塊連續 0xFF,但是這並不表明這個擦寫塊是干凈的。於是我們需要 CLEANMARKER 節點來確切的標識一個干凈的擦寫塊。
JFFS2節點,擦寫塊在內存中的表示和操作
JFFS2 維護了幾個鏈表來管理擦寫塊,根據擦寫塊上的內容,一個擦寫塊會在不同的鏈表上。具體來說,當一個擦寫塊上都是合法(valid)的節點時,它會在 clean_list 上;當一個擦寫塊包含至少一個過時(obsolete)的節點時,它會在 dirty_list 上;當一個擦寫塊被擦寫完畢,並被寫入 CLEANMARKER 節點後,它會在 free_list 上。
通常情況下,JFFS2 順序的在擦寫塊上寫入不同的節點,直到一個擦寫塊被寫滿。此時 JFFS2 從 free_list 上取下一個擦寫塊,繼續從擦寫塊的開頭開始寫入節點。當 free_list 上擦寫塊的數量逐漸減少到一個預先設定的閥值的時候,垃圾回收就被觸發了,為文件系統清理出更多的可用擦寫塊。 為了減少對內存的佔用,JFFS2 並沒有把 i 節點所有的信息都保留在內存中,而只是把那些在請求到來時不能很快獲得的信息保留在內存中。具體來說,對於在快閃記憶體上的每個 i 節點,在內存里都有一個 struct jffs2_inode_cache 與之對應,這個結構里保存了 i 節點號,指向 i 節點的連接數,以及一個指向屬於這個 i 節點的物理節點鏈表的指針。所有的 struct jffs2_inode_cache 存儲在一個哈希表中。快閃記憶體上的每個節點在內存中由一個 struct jffs2_raw_node_ref 表示,這個結構里保存了此節點的物理偏移,總長度,以及兩個指向 struct jffs2_raw_node_ref 的指針。一個指針指向此節點在物理擦寫塊上的下一個節點,另一個指針指向屬於同一個 i-節點的物理節點鏈表的下一個節點。
圖四
在快閃記憶體上的節點的起始偏移都是 4位元組對齊的,所以 struct jffs2_inode_cache 中flash_offset 的最低兩位沒有被用到。JFFS2 正好利用最低位作為此節點是否過時的標記。
下面舉一例來說明 JFFS2 是如何使用這些數據結構的。VFS 調用 iget() 來得到一個 i 節點的信息,當這個 i 節點不在緩存中的時候,VFS 就會調用 JFFS2 的 read_inode() 回調函數來得到 i 節點信息。傳給 read_inode() 的參數是 i 節點號,JFFS2 用這個 i 節點號從哈希表中查找相應的 struct jffs2_inode_cache,然後利用屬於這個 i 節點的節點鏈表從快閃記憶體上讀入節點信息,建立類似於表三的映射信息。
JFFS2 掛載過程
JFFS2 的掛載過程分為四個階段:
1) JFFS2 掃描快閃記憶體介質,檢查每個節點 CRC 校驗碼的合法性,同時分配了 struct jffs2_inode_cache 和 struct jffs2_raw_node_ref
2) 掃描每個 i 節點的物理節點鏈表,標識出過時的物理節點;對每一個合法的dentry節點,將相應的 jffs2_inode_cache 中的 nlink 加一。
3 找出 nlink 為 0 的 jffs2_inode_cache,釋放相應的節點。
4 釋放在掃描過程中使用的臨時信息。
JFFS2 垃圾回收機制
當 free_list 上的擦寫塊數太少了,垃圾回收就會被觸發。垃圾回收主要的任務就是回收那些已經過時的節點,但是除此之外它還要考慮磨損平衡的問題。因為如果一味的從 dirty_list上選取擦寫塊進行垃圾回收,那麼 dirty_list 上的擦寫塊將先於 clean_list 上的擦寫塊被磨損壞。JFFS2 的處理方式是以 99% 的概率從 dirty_list,1% 的概率從 clean_list 上取一個擦寫塊下來。由此可以看出 JFFS2 的設計思想是偏向於性能,同時兼顧磨損平衡。對這個塊上每一個沒有過時的節點執行相同的操作:
1 找出這個節點所屬的 i 節點號(見圖五)。
2 調用 iget(),建立這個 i 節點的文件映射表。
3 找出這個節點上沒有過時的數據內容,並且如果合法的數據太少,JFFS2 還會合並相鄰的節點。
4 將數據讀入倒緩存里,然後將它拷貝到新的擦寫塊上。
5 將回收的節點置為過時。
當擦寫塊上所有的節點都被置為過時,就可以擦寫這個擦寫塊,回收使用它。
『柒』 如何實現一個文件系統
摘要:本文目的是分析在Linux系統中如何實現新的文件系統。在介紹文件系統具體實現前先介紹文件系統的概念和作用,抽象出了文件系統概念模型。熟悉文件系統的內涵後,我們再近一步討論Linux系統中和文件系統的特殊風格和具體文件系統在Linux中組成結構,為讀者勾畫出Linux中文件系統工作的全景圖。最後,我們再通過Linux中最簡單的Romfs作實例分析實現文件系統的普遍步驟。(我們假定讀者已經對Linux文件系統初步了解)
什麼是文件系統
首先要談的概念就是什麼是文件系統,它的作用到底是什麼。
文件系統的概念雖然許多人都認為是再清晰不過的了,但其實我們往往在談論中或多或少地誇大或片縮小了它的實際概念(至少我時常混淆),或者說,有時借用了其它概念,有時說的又不夠全面。
比如在操作系統中,文件系統這個術語往往既被用來描述磁碟中的物理布局,比如有時我們說磁碟中的「文件系統」是EXT2或說把磁碟格式化成FAT32格式的「文件系統」等——這時所說的「文件系統」是指磁碟數據的物理布局格式;另外,文件系統也被用來描述內核中的邏輯文件結構,比如有時說的「文件系統」的介面或內核支持Ext2等「文件系統」——這時所說的文件系統都是內存中的數據組織結構而並非磁碟物理布局。還有些時候說「文件系統」負責管理用戶讀寫文件——這時所說的「文件系統」往往描述操作系統中的「文件管理系統」,也就是文件子系統。
雖然上面我們列舉了混用文件系統的概念的幾種情形,但是卻也不能說上述說法就是錯誤的,因為文件系統概念本身就囊括眾多概念,幾乎可以說在操作系統中自內存管理、系統調度到I/O系統、設備驅動等各個部分都和文件系統聯系密切,有些部分和文件系統甚至未必能明確劃分——所以不能只知道文件系統是系統中數據的存儲結構,一定要全面認識文件系統在操作系統中的角色,才能具備自己開發新文件系統的能力。
為了澄清文件系統的概念,必須先來看看文件系統在操作系統中處於何種角色,分析文件系統概念的內含外延。所以我們先拋開Linux文件系統的實例,而來看看操作系統中文件系統的普遍體系結構,從而增強對文件系統的理論認識。
下面以軟體組成的結構圖[1]的方式描述文件系統所涉及的內容。
我們針對各層做以簡要分析:
首先我們來分析最低層——設備驅動層,該層負責與外設——磁碟等——通訊。基於磁碟的文件系統都需要和存儲設備打交道,而系統操作外設離不開驅動程序。所以內核對文件的最後操作行為就是調用設備驅動程序完成從主存(內存)到輔存(磁碟)的數據傳輸。文件系統相關的多數設備都屬於塊設備,常見的塊設備驅動程序有磁碟驅動,光碟機驅動等,之所以稱它們為塊設備,一個原因是它們讀寫數據都是成塊進行的,但是更重要的原因是它們管理的數據能夠被隨機訪問——不需要向字元設備那樣必須順序訪問。
設備驅動層的上一層是物理I/O層,該層主要作為計算機外部環境和系統的介面,負責系統和磁碟交換數據塊。它要知道據塊在磁碟中存儲位置,也要知道文件數據塊在內存緩沖中的位置,另外它不需要了解數據或文件的具體結構。可以看到這層最主要的工作是標識別磁碟扇區和內存緩沖塊[2]之間的映射關系。
再上層是基礎I/O監督層,該層主要負責選擇文件 I/O需要的設備,調度磁碟請求等工作,另外分配I/O緩沖和磁碟空間也在該層完成。由於塊設備需要隨機訪問數據,而且對速度響應要求較高,所以操作系統不能向對字元設備那樣簡單、直接地發送讀寫請求,而必須對讀寫請求重新優化排序,以能節省磁碟定址時間,另外也必須對請求提交採取非同步調度(尤其寫操作)的方式進行。總而言之,內核對必須管理塊設備請求,而這項工作正是由該層負責的。
倒數第二層是邏輯I/O層,該層允許用戶和應用程序訪問記錄。它提供了通用的記錄(record)I/O操作,同時還維護基本文件數據。由於為了方便用戶操作和管理文件內容,文件內容往往被組織成記錄形式,所以操作系統為操作文件記錄提供了一個通用邏輯操作層。
和用戶最靠近的是訪問方法層,該層提供了一個從用戶空間到文件系統的標准介面,不同的訪問方法反映了不同的文件結構,也反映了不同的訪問數據和處理數據方法。這一層我們可以簡單地理解為文件系統給用戶提供的訪問介面——不同的文件格式(如順序存儲格式、索引存儲格式、索引順序存儲格式和哈希存儲格式等)對應不同的文件訪問方法。該層要負責將用戶對文件結構的操作轉化為對記錄的操作。
對比上面的層次圖我們再來分析一下數據流的處理過程,加深對文件系統的理解。
假如用戶或應用程序操作文件(創建/刪除),首先需要通過文件系統給用戶空間提供的訪問方法層進入文件系統,接著由使用邏輯I/O層對記錄進行給定操作,然後記錄將被轉化為文件塊,等待和磁碟交互。這里有兩點需要考慮——第一,磁碟管理(包括再磁碟空閑區分配文件和組織空閑區);第二,調度塊I/O請求——這些由基礎I/O監督層的工作。再下來文件塊被物理I/O層傳遞給磁碟驅動程序,最後磁碟驅動程序真正把數據寫入具體的扇區。至此文件操作完畢。
當然上面介紹的層次結構是理想情況下的理論抽象,實際文件系統並非一定要按照上面的層次或結構組織,它們往往簡化或合並了某些層的功能(比如Linux文件系統因為所有文件都被看作位元組流,所以不存在記錄,也就沒有必要實現邏輯I/O層,進而也不需要在記錄相關的處理)。但是大體上都需要經過類似處理。如果從處理對象上和系統獨立性上劃分,文件系統體系結構可以被分為兩大部分:——文件管理部分和操作系統I/O部分。文件管理系統負責操作內存中文件對象,並按文件的邏輯格式將對文件對象的操作轉化成對文件塊的操作;而操作系統I/O部分負責內存中的塊與物理磁碟中的數據交換。
數據表現形式再文件操作過程中也經歷了幾種變化:在用戶訪問文件系統看到的是位元組序列,而在位元組序列被寫入磁碟時看到的是內存中文件塊(在緩沖中),在最後將數據寫入磁碟扇區時看到的是磁碟數據塊[3]。
本文所說的實現文件系統主要針對最開始講到第二種情況——內核中的邏輯文件結構(但其它相關的文件管理系統和文件系統磁碟存儲格式也必須了解),我們用數據處理流圖來分析一下邏輯文件系統主要功能和在操作系統中所處的地位。
其中文件系統介面與物理布局管理是邏輯文件系統要負責的主要功能。
文件系統介面為用戶提供對文件系統的操作,比如open、close、read、write和訪問控制等,同時也負責處理文件的邏輯結構。
物理存儲布局管理,如同虛擬內存地址轉化為物理內存地址時,必須處理段頁結構一樣,邏輯文件結構必須轉化到物理磁碟中,所以也要處理物理分區和扇區的實際存儲位置,分配磁碟空間和內存中的緩沖也要在這里被處理。
所以說要實現文件系統就必須提供上面提到的兩種功能,缺一不可。
在了解了文件系統的功能後,我們針對Linux操作系統分析具體文件系統如何工作,進而掌握實現一個文件系統需要的步驟。
Linux 文件系統組成結構
Linux 文件系統的結構除了我們上面所提到的概念結構外,最主要有兩個特點,一個是文件系統抽象出了一個通用文件表示層——虛擬文件系統或稱做VFS。另外一個重要特點是它的文件系統支持動態安裝(或說掛載、登陸等),大多數文件系統都可以作為根文件系統的葉子接點被掛在到根文件目錄樹下的子目錄上。另外Linux系統在文件讀寫的I/O操作上也採取了一些先進技術和策略。
我們先從虛擬文件系統入手分析linux文件系統的特性,然後介紹有關文件系統的安裝、注冊和讀寫等概念。
虛擬文件系統
虛擬文件系統為用戶空間程序提供了文件系統介面。系統中所有文件系統不但依賴VFS共存,而且也依靠VFS系統協同工作。通過虛擬文件系統我們可以利用標準的UNIX文件系統調用對不同介質上的不同文件系統進行讀寫操作[4]。
虛擬文件系統的目的是為了屏蔽各種各樣不同文件系統的相異操作形式,使得異構的文件系統可以在統一的形式下,以標准化的方法訪問、操作。實現虛擬文件系統利用的主要思想是引入一個通用文件模型——該模型抽象出了文件系統的所有基本操作(該通用模型源於Unix風格的文件系統),比如讀、寫操作等。同時實際文件系統如果希望利用虛擬文件系統,既被虛擬文件系統支持,也必須將自身的諸如,「打開文件」、「讀寫文件」等操作行為以及「什麼是文件」,「什麼是目錄」等概念「修飾」成虛擬文件系統所要求的(定義的)形式,這樣才能夠被虛擬文件系統支持和使用。
我們可以借用面向對象的一些思想來理解虛擬文件系統,虛擬文件系統好比一個抽象類或介面,它定義(但不實現)了文件系統最常見的操作行為。而具體文件系統好比是具體類,它們是特定文件系統的實例。具體文件系統和虛擬文件系統的關系類似具體類繼承抽象類或實現介面。而在用戶看到或操作的都是抽象類或介面,但實際行為卻發生在具體文件系統實例上。至於如何將對虛擬文件系統的操作轉化到對具體文件系統的實例,就要通過注冊具體文件系統到系統,然後再安裝具體文件系統才能實現轉化,這點可以想像成面向對象中的多態概念。
我們個實舉例來說明具體文件系統如何通過虛擬文件系統協同工作。
例如:假設一個用戶輸入以下shell命令:
$ cp /hda/test1 /removable/test2
其中 /removable是MS-DOS磁碟的一個安裝點,而 /hda 是一個標準的第二擴展文件系統( Ext2)的目錄。cp命令不用了解test1或test2的具體文件系統,它所看到和操作的對象是VFS。cp首先要從ext3文件系統讀出test1文件,然後寫入MS-DOS文件系統中的test2。VFS會將找到ext3文件系統實例的讀方法,對test1文件進行讀取操作;然後找到MS-DOS(在Linux中稱VFAT)文件系統實例的寫方法,對test2文件進行寫入操作。可以看到 VFS是讀寫操作的統一界面,只要具體文件系統符合VFS所要求的介面,那麼就可以毫無障礙地透明通訊了。
Unix風格的文件系統
虛擬文件系統的通用模型源於Unix風格的文件系統,所謂Unix風格是指Unix傳統上文件系統傳統上使用了四種和文件系統相關的抽象概念:文件(file)、目錄項(dentry)、索引節點(inode)和安裝點(mount point)。
文件——在Unix中的文件都被看做是一有序位元組串,它們都有一個方便用戶或系統識別的名稱。另外典型的文件操作有讀、寫、創建和刪除等。
目錄項——不要和目錄概念搞混淆,在Linux中目錄被看作文件。而目錄項是文件路徑中的一部分。一個文件路徑的例子是「/home/wolfman/foo」——根目錄是/,目錄home,wolfman和文件foo都是目錄項。
索引節點——Unix系統將文件的相關信息(如訪問控制許可權、大小、擁有者、創建時間等等信息),有時被稱作文件的元數據(也就是說,數據的數據)被存儲在一個單獨的數據結構中,該結構被稱為索引節點(inode)。
安裝點——在Unix中,文件系統被安裝在一個特定的安裝點上,所有的已安裝文件系統都作為根文件系統樹中的葉子出現在系統中。
上述概念是Unix文件系統的邏輯數據結構,但相應的Unix文件系統(Ext2等)磁碟布局也實現了部分上述概念,比如文件信息(文件數據元)存儲在磁碟塊中的索引節點上。當文件被載如內存時,內核需要使用磁碟塊中的索引點來裝配內存中的索引接點。類似行為還有超級塊信息等。
對於非Unix風格文件系統,如FAT或NTFS,要想能被VFS支持,它們的文件系統代碼必須提供這些概念的虛擬形式。比如,即使一個文件系統不支持索引節點,它也必須在內存中裝配起索引節點結構體——如同本身固有一樣。或者,如果一個文件系統將目錄看作是一種特殊對象,那麼要想使用VFS,必須將目錄重新表示為文件形式。通常,這種轉換需要在使用現場引入一些特殊處理,使得非Unix文件系統能夠兼容Unix文件系統的使用規則和滿足VFS的需求。通過這些處理,非Unix文件系統便可以和VFS一同工作了,是性能上多少會受一些影響[5]。這點很重要,我們實現自己文件系統時必須提供(模擬)Unix風格文件系統的抽象概念。
Linux文件系統中使用的對象
Linux文件系統的對象就是指一些數據結構體,之所以稱它們是對象,是因為這些數據結構體不但包含了相關屬性而且還包含了操作自身結構的函數指針,這種將數據和方法進行封裝的思想和面向對象中對象概念一致,所以這里我們就稱它們是對象。
Linux文件系統使用大量對象,我們簡要分析以下VFS相關的對象,和除此還有和進程相關的一些其它對象。
VFS相關對象
這里我們不展開討論每個對象,僅僅是為了內容完整性,做作簡要說明。
VFS中包含有四個主要的對象類型,它們分別是:
超級塊對象,它代表特定的已安裝文件系統。
索引節點對象,它代表特定文件。
目錄項對象,它代表特定的目錄項。
文件對象,它代表和進程打開的文件。
每個主要對象中都包含一個操作對象,這些操作對象描述了內核針對主要對象可以使用的方法。最主要的幾種操作對象如下:
super_operations對象,其中包括內核針對特定文件系統所能調用的方法,比如read_inode()和sync_fs()方法等。
inode_operations對象,其中包括內核針對特定文件所能調用的方法,比如create()和link()方法等。
dentry_operations對象,其中包括內核針對特定目錄所能調用的方法,比如d_compare()和d_delete()方法等。
file對象,其中包括,進程針對已打開文件所能調用的方法,比如read()和write()方法等。
除了上述的四個主要對象外,VFS還包含了許多對象,比如每個注冊文件系統都是由file_system_type對象表示——描述了文件系統及其能力(如比如ext3或XFS);另外每一個安裝點也都利用vfsmount對象表示——包含了關於安裝點的信息,如位置和安裝標志等。
其它VFS對象
系統上的每一進程都有自己的打開文件,根文件系統,當前工作目錄,安裝點等等。另外還有幾個數據結構體將VFS層和文件的進程緊密聯系,它們分別是:file_struct 和fs_struct
file_struct結構體由進程描述符中的files項指向。所有包含進程的信息和它的文件描述符都包含在其中。第二個和進程相關的結構體是fs_struct。該結構由進程描述符的fs項指向。它包含文件系統和進程相關的信息。每種結構體的詳細信息不在這里說明了。
緩存對象
除了上述一些結構外,為了縮短文件操作響應時間,提高系統性能,Linux系統採用了許多緩存對象,例如目錄緩存、頁面緩存和緩沖緩存(已經歸入了頁面緩存),這里我們對緩存做簡單介紹。
頁高速緩存(cache)是 Linux內核實現的一種主要磁碟緩存。其目的是減少磁碟的I/O操作,具體的講是通過把磁碟中的數據緩存到物理內存中去,把對磁碟的I/O操作變為對物理內存的I/O操作。頁高速緩存是由RAM中的物理頁組成的,緩存中每一頁都對應著磁碟中的多個塊。每當內核開始執行一個頁I/O操作時(通常是對普通文件中頁大小的塊進行磁碟操作),首先會檢查需要的數據是否在高速緩存中,如果在,那麼內核就直接使用高速緩存中的數據,從而避免了訪問磁碟。
但我們知道文件系統只能以每次訪問數個塊的形式進行操作。內核執行所有磁碟操作都必須根據塊進行,一個塊包含一個或多個磁碟扇區。為此,內核提供了一個專門結構來管理緩沖buffer_head。緩沖頭[6]的目的是描述磁碟扇區和物理緩沖之間的映射關系和做I/O操作的容器。但是緩沖結構並非獨立存在,而是被包含在頁高速緩存中,而且一個頁高速緩存可以包含多個緩沖。我們將在文件後面的文件讀寫部分看到數據如何被從磁碟扇區讀入頁高速緩存中的緩沖中的。
文件系統的注冊和安裝
使用文件系統前必須對文件系統進行注冊和安裝,下面分別對這兩種行為做簡要介紹。
文件系統的注冊
VFS要想能將自己定義的介面映射到實際文件系統的專用方法上,必須能夠讓內核識別實際的文件系統,實際文件系統通過將代表自身屬性的文件類型對象(file_system_type)注冊(通過register_filesystem()函數)到內核,也就是掛到內核中的文件系統類型鏈表上,來達到使文件系統能被內核識別的目的。反過來內核也正是通過這條鏈表來跟蹤系統所支持的各種文件系統的。
我們簡要分析一下注冊步驟:
struct file_system_type {
const char *name; /*文件系統的名字*/
int fs_flags; /*文件系統類型標志*/
/*下面的函數用來從磁碟中讀取超級塊*/
struct super_block * (*read_super) (struct file_system_type *, int,
const char *, void *);
struct file_system_type * next; /*鏈表中下一個文件系統類型*/
struct list_head fs_supers; /*超級塊對象鏈表*/
};
其中最重要的一項是read_super()函數,它用來從磁碟上讀取超級塊,並且當文件系統被裝載時,在內存中組裝超級塊對象。要實現一個文件系統首先需要實現的結構體便是file_system_type結構體。
注冊文件系統只能保證文件系統能被系統識別,但此刻文件系統尚不能使用,因為它還沒有被安裝到特定的安裝點上。所以在使用文件系統前必須將文件系統安裝到安裝點上。
文件系統被實際安裝時,將在安裝點創建一個vfsmount結構體。該結構體用代表文件系統的實例——換句話說,代表一個安裝點。
vfsmount結構被定義在<linux/mount.h>中,下面是具體結構
―――――――――――――――――――――――――――――――――――――――
struct vfsmount
{
struct list_head mnt_hash; /*哈希表*/
struct vfsmount *mnt_parent; /*父文件系統*/
struct dentry *mnt_mountpoint; /*安裝點的目錄項對象*/
struct dentry *mnt_root; /*該文件系統的根目錄項對象*/
struct super_block *mnt_sb; /*該文件系統的超級塊*/
struct list_head mnt_mounts; /*子文件系統鏈表*/
struct list_head mnt_child; /*和父文件系統相關的子文件系統*/
atomic_t mnt_count; /*使用計數*/
int mnt_flags; /*安裝標志*/
char *mnt_devname; /*設備文件名字*/
struct list_head mnt_list; /*描述符鏈表*/
};
――――――――――――――――――――――――――――――――――――――
文件系統如果僅僅注冊,那麼還不能被用戶使用。要想使用它還必須將文件系統安裝到特定的安裝點後才能工作。下面我們接著介紹文件系統的安裝[7]過程。
安裝過程
用戶在用戶空間調用mount()命令——指定安裝點、安裝的設備、安裝類型等——安裝指定文件系統到指定目錄。mount()系統調用在內核中的實現函數為sys_mount(),該函數調用的主要常式是do_mount(),它會取得安裝點的目錄項對象,然後調用do_add_mount()常式。
do_add_mount()函數主要做的是首先使用do_kern_mount()函數創建一個安裝點,再使用graft_tree()將安裝點作為葉子與根目錄樹掛接起來。
整個安裝過程中最核心的函數就是do_kern_mount()了,為了創建一個新安裝點(vfsmount),該函數需要做一下幾件事情:
l 1 檢查安裝設備的權利,只有root許可權才有能力執行該操作。
l 2 Get_fs_type()在文件鏈表中取得相應文件系統類型(注冊時被填加到練表中)。
l 3 Alloc_vfsmnt()調用slab分配器為vfsmount結構體分配存儲空間,並把它的地址存放在mnt局部變數中。
l 4 初始化mnt->mnt_devname域
l 5 分配新的超級塊並初始化它。do_kern_mount( )檢查file_system_type描述符中的標志以決定如何進行如下操作:根據文件系統的標志位,選擇相應的方法讀取超級塊(比如對Ext2,romfs這類文件系統調用get_sb_dev();對於這種沒有實際設備的虛擬文件系統如 ramfs調用get_sb_nodev())——讀取超級塊最終要使用文件系統類型中的read_super方法。
安裝過程做的最主要工作是創建安裝點對象,掛接給定文件系統到根文件系統的指定接點下,然後初始化超級快對象,從而獲得文件系統基本信息和相關操作方法(比如讀取系統中某個inode的方法)。
總而言之,注冊過程是告之內核給定文件系統存在於系統內;而安裝是請求內核對給定文件系統進行支持,使文件系統真正可用。
轉載
『捌』 簡述微軟的FAT32文件系統
FAT32是分區格式的一種。這種格式採用32位的文件分配表,使其對磁碟的管理能力大大增強,突破了FAT16對每一個分區的容量只有2 GB的限制。由於現在的硬碟生產成本下降,其容量越來越大,運用FAT32的分區格式後,我們可以將一個大硬碟定義成一個分區而不必分為幾個分區使用,大大方便了對磁碟的管理。但由於FAT32分區內無法存放大於4GB的單個文件,且性能不佳,易產生磁碟碎片。目前已被性能更優異的NTFS分區格式所取代。
分區標識: 0x0B, 0x0C(MBR)EBD0A0A2-B9E5-4433-87C0-68B6B72699C7(GPT)
最大單文件大小: 4 GB (Fat16分區是2 GB )
最大文件數量: 268,435,437
最長檔名限制: 8.3 或者 長文件名255個字元
最大卷大小: 8 TB (在windows 2000和windows XP環境下格式化程序只能創建最大32GBFAT32文件系統,不過可以用如PQ等分區軟體分出大於32GB的FAT32分區,大於32GB的FAT32分區在WIN2000/XP下使用完全正常)
記錄日期: 創建、修改、訪問
日期范圍: 1980年1月1日至2107年12月31日
屬性: 只讀,隱藏,系統,卷標,子目錄,檔案
透明加密:不支持
透明壓縮:不支持
訪問許可:無限制
性能特點
編輯
FAT32(File Allocation Table)具有一個最大的優點:在一個不超過8GB 的分區中,FAT32分區格式的每個簇容量都固定為4KB,與FAT16相比,可以大大地減少磁碟的浪費,提高磁碟利用率。目前,支持這一磁碟分區格式的操作系統有Win95、Win98、Win2000、Win2003、Win Vista、Win7和Win10。部分智能手機也支持對FAT32格式存儲器的直接讀寫(OTG)。但是,這種分區格式也有它的缺點,首先是採用FAT32格式分區的磁碟,由於文件分配表的擴大,運行速度比採用FAT16格式分區的磁碟要慢。
約束
編輯
windows 2000和windows XP能夠讀寫任何大小的FAT32文件系統,但是這些平台上的格式化程序只能創建最大32GB的FAT32文件系統。
在dos系統下可直接訪問fat32分區,而ntfs分區則不能在dos下直接訪問。
缺點
編輯
但FAT有一個嚴重的缺點:當文件刪除後寫入新資料,FAT不會將檔案整理成完整片段再寫入,長期使用後會使檔案資料變得逐漸分散,而減慢了讀寫速度。硬碟碎片整理是一種解決方法,但必須經常整理來保持FAT文件系統的效率。還有就是FAT32分區因為設計缺陷,無法支持超過4GB的單個文件.
磁碟結構
編輯
主啟動區 文件 分配表 #1 文件 分配表 #2 根目錄 其他所有資料...剩下磁碟空間
一個FAT文件系統包括四個不同的部分。
保留扇區
位於最開始的位置。第一個保留扇區是引導區(分區啟動記錄)。它包括一個稱為基本輸入輸出參數塊的區域(包括一些基本的文件系統信息尤其是它的類型和其它指向其它扇區的指針),通常包括操作系統的啟動調用代碼。保留扇區的總數記錄在引導扇區中的一個參數中。引導扇區中的重要信息可以被DOS和OS/2中稱為驅動器參數塊的操作系統結構訪問。
FAT區域
它包含有兩份文件分配表,這是出於系統冗餘考慮,盡管它很少使用,即使是磁碟修復工具也很少使用它。它是分區信息的映射表,指示簇是如何存儲的。
根目錄區域
它是在根目錄中存儲文件和目錄信息的目錄表。在FAT32下它可以存在分區中的任何位置,但是在早期的版本中它永遠緊隨FAT區域之後。
數據區域
這是實際的文件和目錄數據存儲的區域,它占據了分區的絕大部分。通過簡單地在FAT中添加文件鏈接的個數可以任意增加文件大小和子目錄個數(只要有空簇存在)。然而需要注意的是每個簇只能被一個文件佔有,這樣的話如果在32KB大小的簇中有一個1KB大小的文件,那麼31KB的空間就浪費掉了。
啟動扇區
編輯
格式如下
偏移(位元組) 長度(位元組) 說明
0x00 3 跳轉指令(跳過開頭一段區域)
0x03 8 OEM名稱(空格補齊)。 MS-DOS檢查這個區域以確定使用啟動記錄中的哪一部分數據。常見值是IBM 3.3(在「IBM」和「3.3」之間有兩個空格)和MSDOS5.0.
0x0b 2 每個扇區的位元組數。基本輸入輸出系統參數塊從這里開始。
0x0d 1 每簇扇區數
0x0e 2 保留扇區數(包括啟動扇區)
0x10 1 文件分配表數目
0x11 2 最大根目錄條目個數
0x13 2 總扇區數(如果是0,就使用偏移0x20處的4位元組值)
0x15 1 介質描述 0xF8 單面、每面80磁軌、每磁軌9扇區
0xF9 雙面、每面80磁軌、每磁軌9扇區
0xFA 單面、每面80磁軌、每磁軌8扇區
0xFB 雙面、每面80磁軌、每磁軌8扇區
0xFC 單面、每面40磁軌、每磁軌9扇區
0xFD 雙面、每面40磁軌、每磁軌9扇區
0xFE 單面、每面40磁軌、每磁軌8扇區
0xFF 雙面、每面40磁軌、每磁軌8扇區
同樣的介質描述必須在重復復制到每份FAT的第一個位元組。有些操作系統(MSX-DOS 1.0版)全部忽略啟動扇區參數,而僅僅使用FAT的第一個位元組的介質描述確定文件系統參數。
0x16 2 每個文件分配表的扇區(FAT16)
0x18 2 每磁軌的扇區
0x1a 2 磁頭數
0x1c 4 隱藏扇區
0x20 4 總扇區數(如果超過65535,參見偏移0x13)
0x24 4 每個文件分配表的扇區(FAT32)。擴展基本輸入輸出系統參數塊從這里開始。
0x24 1 物理驅動器個數(FAT16)
0x25 1 當前磁頭(FAT16)
0x26 1 簽名(FAT16)
0x27 4 ID (FAT16)
0x28 2 Flags (FAT32)
0x2a 2 版本號 (FAT32)
0x2c 4 根目錄啟始簇 (FAT32)
0x2b 11 卷標(非FAT32)
0x30 2 FSInfo 扇區 (FAT32)
0x32 2 啟動扇區備份 (FAT32)
0x34 2 保留未使用 (FAT32)
0x36 8 FAT文件系統類型(如FAT、FAT12、FAT16)
0x3e 2 操作系統自引導代碼
0x40 1 BIOS設備代號 (FAT32)
0x41 1 未使用 (FAT32)
0x42 1 標記 (FAT32)
0x43 4 卷序號 (FAT32)
0x47 11 卷標(FAT32)
0x52 8 FAT文件系統類型(FAT32)
0x1FE 2 扇區結束符(0x55 0xAA)
這里描述的啟動扇區能在如OS/2 1.3的啟動盤上看到。早期的版本使用一個較短的基本輸入輸出系統參數塊,它們的啟動代碼在前面開始(如OS/2 1.1中是偏移0x2b)。
分配表
編輯
一個分區分成同等大小的簇,也就是連續空間的小塊。簇的大小隨著FAT文件系統的類型以及分區大小而不同,典型的簇大小介於2KB到32KB之間。每個文件根據它的大小可能佔有一個或者多個簇;這樣,一個文件就由這些(稱為單鏈表)簇鏈所表示。然而,這些鏈並不一定一個接著一個在磁碟上存儲,它們經常是在整個數據區域零散的儲存。
文件分配表(FAT)是映射到分區每個簇的條目列表。每個條目記錄下面五種信息中的一種。
●鏈中下一個簇的地址
●一個特殊的文件結束符(EOF)符號指示鏈的結束
●一個特殊的符號標示壞簇
●一個特殊的符號標示保留簇
●0來表示空閑簇
FAT32條目值:
FAT32 描述
0x?0000000 空閑簇
0x?0000001 保留簇
0x?0000002 - 0x?FFFFFEF 被佔用的簇;指向下一個簇
0x?FFFFFF0 - 0x?FFFFFF6 保留值
0x?FFFFFF7 壞簇
0x?FFFFFF8 - 0x?FFFFFFF 文件最後一個簇
注意FAT32隻使用32位中的28位。高4位通常是0但它們是保留位,不要更改它們。在上面的表中它們用問號表示。
目錄表
編輯
目錄表是一個表示目錄的特殊類型文件(現今通常稱為文件夾)。它裡面保存的每個文件或目錄使用表中的32位條目表示。每個條目記錄名字、擴展名、屬性(檔案、目錄、隱藏、只讀、系統和卷)、創建的日期和時間、文件/目錄數據第一個簇的地址,最後是文件/目錄的大小。
除了FAT12和FAT16文件系統中的根目錄表占據特殊的根目錄區域位置之外,所有其它的目錄表都存在數據區域。
合法的DOS文件名包括下面一些字元:
●大寫字母A-Z
●數字0-9
●空格(盡管結尾的空格被作為填充而不是文件名的一部分)
●! # $ amp;amp; ( ) - @ ^ _ ` { } ~ '
●數值 128-255
●DOS文件名位於OEM字元集。
長文件名(LFN)使用一個技巧存儲在FAT文件系統上——在目錄表中添加假的條目。這些條目使用一個普通文件無法使用的卷標屬性標識,普通文件無法使用是由於它們被大多數舊的MS-DOS程序忽略。很顯然,一個只包含卷標的目錄被當作空卷,這樣就允許刪除;使用長文件名創建的文件在從普通的DOS刪除就會發生這樣的情形。
校驗和也允許檢驗長文件名是否與8.3文件名匹配;當一個文件刪除之後使用DOS在同一個目錄位置重新創建之後就會出現不匹配現象。校驗和使用下面的演算法計算。(注意pFcbName是指向如正常目錄條目中所顯示的文件名的指針,例如前八個字元是文件名,最後三個是擴展名。點是隱含的。文件名中沒有使用的空間將使用空格(ASCII 0x20)補齊。例如,「Readme.txt」將記錄為"README TXT"。
特點
編輯
FAT32實際上是文件分區表採取的一種形式,它是相對於FAT16而言的。眾所周知,Dos和Windows95採用的都是FAT16格式。至於FAT32,准確地說是在Windows95OSR2中第一次出現的,之所以沒有宣傳是因為當時該文件系統還不夠成熟,尚處於試探階段。那麼為什麼一定要推出FAT32呢?這主要是由其自身的優越性決定的。
首先,它可以大大地節約磁碟空間。文件在磁碟上是以簇的方式存放的,簇里存放了一個文件就不能再存放另外的文件。假如一個磁碟的分區大小為512MB,基於FAT16的系統的簇的大小為8KB,而FAT32系統的簇的大小僅是4KB,那麼,我們存放一個3KB的文件,FAT16系統就會有5KB的空間被浪費,而FAT32的浪費則會少一些。如果分區達到1GB,FAT16的簇為16KB,而FAT32還是4KB,節省的也就更多了。
在推出FAT32文件系統之前,通常PC機使用的文件系統是FAT16。像基於MS-DOS,Win 95等系統都採用了FAT16文件系統。在Win 9X下,FAT16支持的分區最大為2GB。我們知道計算機將信息保存在硬碟上稱為「簇」的區域內。使用的簇越小,保存信息的效率就越高。在FAT16的情況下,分區越大簇就相應的要增大,存儲效率就越低,勢必造成存儲空間的浪費。並且隨著計算機硬體和應用的不斷提高,FAT16文件系統已不能很好地適應系統的要求。在這種情況下,推出了增強的文件系統FAT32。同FAT16相比,FAT32主要具有以下特點:
1. 同FAT16相比FAT32最大的優點是可以支持的磁碟大小達到2TB(2048GB),但是不能支持小於512MB的分區。基於FAT32的Win 2000可以支持分區最大為32GB;而基於 FAT16的Win 2000支持的分區最大2GB。
2. 由於採用了更小的簇,FAT32文件系統可以更有效率地保存信息。如兩個分區大小都為2GB,一個分區採用了FAT16文件系統,另一個分區採用了FAT32文件系統。採用FAT16的分區的簇大小為32KB,而FAT32分區的簇只有4KB的大小。這樣FAT32就比FAT16的存儲效率要高很多,通常情況下可以提高15%。
3. FAT32文件系統可以重新定位根目錄和使用FAT的備份副本。另外FAT32分區的啟動記錄被包含在一個含有關鍵數據的結構中,減少了計算機系統崩潰的可能性。
稍作補充:
功能
編輯
與以前的 FAT 文件系統實現相比,FAT32 提供了以下增強功能:FAT32 支持最大為 2 TB 的驅動器。
注意:Microsoft Windows 2000 僅能支持最大為 32 GB 的 FAT32 分區。
· FAT32 可以更高效地使用空間。FAT32 使用較小的簇(即,對於大小在 8 GB 以內的驅動器,使用 4 KB 的簇),這與大的 FAT 或 FAT16 驅動器相比,可將磁碟空間的使用率提高10% 到 15%。
· FAT32 更穩定可靠。FAT32 可以重新定位根文件夾,而且它使用文件分配表的備份副本,而不是使用默認副本。此外,FAT32 驅動器上的引導記錄也得到擴展,包括了關鍵數據結構的備份副本。因此,與現有的 FAT16 驅動器相比,FAT32 驅動器不容易受單點故障的影響。
· FAT32 更靈活。FAT32 驅動器上的根文件夾是普通的簇鏈,因此它可以位於驅動器上的任何位置。以前對根文件夾數量的限制不復存在。此外,可以禁用文件分配表鏡像,這樣就可以讓文件分配表的副本而不是讓第一個文件分配表處於活動狀態。這些功能允許您動態重調 FAT32 分區的大小。不過要注意,雖然 FAT32 的設計允許這一功能,但 Microsoft 將不在初始版本中實現此功能。
兼容性
編輯
軟硬體的兼容問題
為了與現有程序、網路和設備驅動程序保持最大程度的兼容性,FAT32 盡可能不改動現有的 Windows 體系結構、內部數據結構、應用程序編程介面(API) 和磁碟上的格式。然而,因為需要 4 位元組來存儲簇值,所以許多內部的和磁碟上的數據結構以及發布的 API 都作了修改或擴展。某些情況下,現有的 API 無法在 FAT32 驅動器上運行。大多數程序不會受這些更改的影響。現有工具和驅動程序在 FAT32 驅動器上應能夠繼續正常運行。不過,MS-DOS 塊設備驅動程序(例如 Aspidisk.sys)和磁碟工具需要經過修改才能支持 FAT32 驅動器。
所有 Microsoft 捆綁磁碟工具(格式化、Fdisk、碎片整理、基於 MS-DOS 和 Windows 的磁碟掃描)已經過修改,可以在 FAT32 中正常運行。此外,Microsoft 正在與一些主要設備驅動程序和磁碟工具廠商協作,幫助他們修改其產品以支持 FAT32。
注意:不能使用 Microsoft DriveSpace 或 DriveSpace 3 壓縮 FAT32 卷。
FAT32 性能
轉換到 FAT32 文件系統是您可以在基於 Windows 98 的計算機上實現的最大的一種性能增強。
雙啟動計算機
目前,在 Microsoft 操作系統中,只有 Windows 95 OSR2、Windows 98、Windows 2000 和 Windows Me 可以訪問 FAT32 卷。MS-DOS、Windows 95 原始版和 Windows NT 4.0不識別 FAT32 分區,它們無法從 FAT32 卷啟動。此外,如果使用其他操作系統(例如,Windows 95 或 MS-DOS 啟動盤)啟動計算機,也無法正確訪問 FAT32 卷。
Windows 95 OSR2 和 Windows 98 可以在實模式下啟動(例如為了運行游戲)並可以使用 FAT32 卷。
創建 FAT32 驅動器
在 Windows 95 OSR2、Windows 98 和 Windows Me 中,如果在大小超過 512 兆位元組 (MB) 的硬碟上運行 Fdisk 工具,Fdisk 將提示您是否啟用大磁碟支持。如果回答「是」(啟用大磁碟支持),您創建的任何大於 512 MB 的分區都將被標記為 FAT32 分區。
Windows 98 和 Windows Me 中還帶有一種 FAT32 轉換工具,您可以使用該工具將現有驅動器轉換為 FAT32 文件系統。要使用該轉換工具,請按照下列步驟操作: 1. 單擊開始,依次指向程序、附件、系統工具,然後單擊驅動器轉換器 (FAT32)。
2. 單擊下一步。
3. 單擊希望轉換為 FAT32 文件系統的驅動器,然後單擊下一步。
4. 按照屏幕上的說明操作。
支持范圍
Microsoft 將支持 FAT32 文件系統的功能,以實現無錯讀取和在實模式或保護模式下保存文件。Microsoft 支持 Windows 95 中所帶的實模式和保護模式工具。
對於舊式(較早的)程序,如果它們無法在 FAT32 卷上安裝,或者無法正確保存文件或讀取文件,則您必須與軟體包的生產廠商聯系。
注意:雖然 FAT32 文件系統所支持的硬碟容量最高可以達到 2 TB,但有些硬碟可能會因為計算機基本輸入/輸出系統 (BIOS) INT13 介面的限制而無法包含大於 7.8 GB 的可啟動分區。請與硬體製造商聯系,以確定您計算機的 BIOS 是否支持更新後的 INT13 擴展。
Windows 操作系統使用 FAT32 文件系統時存在以下限制: · 簇不能是 64 千位元組 (KB) 或更大。如果簇為 64 KB 或更大,有些程序(例如安裝程序)在計算磁碟空間時可能會出錯。
· 卷必須包含至少 65,527 個簇,才能使用 FAT32 文件系統。您不能增加使用 FAT32 文件系統的卷上的簇大小,以致於該卷的最終簇數小於 65,527。
· 在使用 FAT32 文件系統的卷上,簇最多是 268,435,445 個。對於文件分配表 (FAT) 的空間,每簇最大為 32 KB,據此計算出的最大磁碟大小大約為 8 太位元組 (TB)。
· Microsoft Windows 95 和 Microsoft Windows 98 附帶的「磁碟掃描」工具是 16 位程序。這樣的程序有一個內存塊,該內存塊的最大分配大小等於 16 MB 減去 64 KB。因此,Windows 95 或 Windows 98 的「磁碟掃描」工具無法處理使用 FAT32 文件系統(其 FAT 大小大於 16 MB 和 64 KB 之差)的卷。使用 FAT32 文件系統的卷上的 FAT 項使用 4 位元組,因此 ScanDisk 無法處理使用定義的簇數大於 4,177,920(包括兩個保留的簇)的 FAT32 文件系統的卷上的 FAT。將 FAT 本身包括在內,按每簇最大 32 KB 計算,卷大小為 127.53 吉位元組 (GB)。
· 您不能減少使用 FAT32 文件系統的卷上的簇大小,以致於 FAT 的最終大小大於 16 MB 與 64 KB 之差。
· 在 Windows 2000 中您無法使用 FAT32 文件系統格式化大於 32 GB 的卷。Windows 2000 FastFAT 驅動程序可以安裝和支持使用 FAT32 文件系統且大於 32 GB的卷(受到其他限制),但是您不能使用格式化工具創建一個這樣的卷。這種現象是設計使然。如果需要創建大於 32 GB 的卷,請改用 NTFS 文件系統。
備註:在嘗試格式化大於 32 GB 的 FAT32 分區時,在進程快結束時格式化會失敗,並出現以下錯誤:
Logical Disk Manager:Volume size too big.
Windows XP 中 FAT32 文件系統的限制
當您在 Windows XP 中使用 FAT32 文件系統時,請注意下列限制: · 簇不能等於或大於 64 KB。如果簇大小為 64 KB 或更大,則有些程序(例如安裝程序)可能會不正確地計算磁碟空間。
· FAT32 卷必須至少包含 65,527 個簇。您不能增加使用 FAT32 文件系統的卷上的簇大小,這樣會導致卷上的簇數少於 65,527 個。
· 如果考慮到以下可變因素,則最大磁碟大小大約為 8 TB:一個 FAT32 卷上允許的最大簇數為 268,435,445,每個簇最大為 32 KB,另外還有文件分配表 (FAT) 所需的空間。
· 您不能減少 FAT32 卷上的簇大小,這樣會導致 FAT 的大小大於 16 MB 減去 64 KB。
· 在 Windows XP 安裝過程中,您不能使用 FAT32 文件系統格式化大於 32 GB 的卷。Windows XP 可以裝入和支持大於 32 GB 的 FAT32 卷(受到其他限制),但是您不能在安裝期間使用 Format 工具創建大於 32 GB 的 FAT32 卷。如果您需要格式化大於 32 GB 的卷,請使用 NTFS 文件系統來格式化。另一種方法是從 Microsoft Windows 98 或 Microsoft Windows Millennium Edition (Me) 啟動盤啟動,然後使用該磁碟上包含的 Format 工具。
有關如何使用 Microsoft Windows 98 或 Microsoft Windows Millennium Edition (Me) 啟動盤格式化硬碟的其他信息,請單擊下面的文章編號,以查看 Microsoft 知識庫中相應的文章:
255867 如何使用 Fdisk 和 Format 工具對硬碟進行分區或重新分區
注意:當您在 Windows XP 安裝過程中試圖格式化大於 32GB 的 FAT32 分區時,在格式化過程快結束時操作將會失敗,並且您可能會收到以下錯誤信息:
Logical Disk Manager:Volume size too big.
· MS-DOS(Microsoft Windows 95 的原始版本)和 Microsoft Windows NT 4.0 及更低版本都不能識別 FAT32 分區,因此無法從 FAT32 卷啟動。
· 您不能在 FAT32 分區上創建大於 (2^32)-1 位元組(即 4 GB 減去 1 個位元組)的文件。
FAT32格式理論上可以支持128TB的磁碟,即簇的大小乘簇的數量32K*(2^32),但由於受到軟硬體的限制和其他方面的原因,不可能達到理論值。
FAT32數據恢復原理
由於FAT與FDT對數據的鏈式存儲管理的,可以通過鏈式搜索查找。只有FAT表和FDT配合使用,才能可以統一管理整個磁碟文件,也就可以准確定位被刪除的文件的確切位置。
在 Window操作系統下對文件的刪除工作,是將FDT中該文件的第一個字元改「E5」來表示該文件已經刪除,同時改寫引導扇區的第二個扇區中表示該分區點用空間大小的相應信息。因此,在設計的時候,根據其存儲結構,對相應的地方進行修改,搜索E5刪除標志,再按被刪文件數據鏈進行恢復。
具體步驟如下:
(1) 獲取磁碟分區類型,分區存儲空間,FAT、FDT、文件等存儲的起始扇區。
(2) 獲取FAT、FDT表項內的簇信息,即簇的刪除、未使用、壞簇、以及文件佔用簇的起始扇區信息等。
(3) 通過FAT、FDT計算不同文件在物理扇區的起始位置,包括有標識E5的刪除文件起始位置、文件類型、佔用大小和存儲的所在簇。
(4) 改變刪除位,通過第3步得到的結果,並按FAT表對文件進行鏈式查找並緩存,當達到文件所在簇尾時,停止操作。
(5) 對存儲的數據進行轉換,生成文件。
(6) 對文件進行異區存儲。 而操作系統在讀寫文件時,會根據FDT中的起始單元,結合FAT表就可以知道文件在磁碟的具體位置,然後順序讀取每個簇的內容,文件的查找如圖4-1所示。具體的方法如下:
(1)在文件目錄項FDT中找到存放在FAT表中的文件File的地址M(2)2*M得到FAT表中File文件數據鏈表首地址B。
(3)在FAT表中的B地址中,存放有文件FILE數據鏈表頭P。
(4)P*4得到在FAT表項中的下一個偏移位置,即下一個數據鏈表。
(5)如果下一個數據鏈表內的信息為0FFFFFFH,則表示文件存儲已經結束圖4-1查找文件流程需要說明的是,新建文件時,系統在FAT表中查找未用的簇記錄在新文件目錄項中做為首簇;FDT文件目錄項中,第0~7位元組為文件名(若有剩餘位元組用20填充)第1位元組表明了該文件的狀態,第1位元組又表明了文件的狀態,00HE5H及其它字元。當該位元組為00H時,表示該目錄項是空表項,可以使用。當為E5H時,表示該目錄項以前用過,但是文件被已經刪除了。
小知識
編輯
在FAT32下,一個目錄只能夠容納65536個文件。微軟的官方文檔沒有給出。
『玖』 文件系統中分配存儲空間的基本單位是什麼
以塊為單位進行的。
為了提高存儲空間的利用率,對存儲空間的分配,通常是採用離散分配方式,以減少外存零頭,並以盤塊為基本分配單位。盤塊的大小通常為 1~8KB。
文件系統中,用於文件的描述和控制並與文件一一對應的是文件控制塊。文件存儲空間的管理就是塊空間的管理,包括空閑塊的分配、回收和組織等幾個問題。
(9)鏈表文件系統擴展閱讀:
位示圖是利用二進制的一位來表示磁碟中一個盤塊的使用情況。當其值為「0」時,表示對應的盤塊空閑;為「1」時,表示已分配。有的系統把「0」作為盤塊已分配的標志,把「1」作為空閑標志。(它們在本質上是相同的,都是用一位的兩種狀態來標志空閑和已分配兩種情況。)
磁碟上的所有盤塊都有一個二進制位與之對應,這樣,由所有盤塊所對應的位構成一個集合,稱為位示圖。通常可用 m × n 個位數來構成位示圖,並使 m × n 等於磁碟的總塊數。位示圖也可描述為一個二維數組 map:Var map: array of bit;
『拾』 在linux操作系統內核實現里經常使用的紅黑樹
在linux操作系統內核實現里經常使用的紅黑樹如下:
二叉樹,按中序遍歷後為一遞增數組,自平衡意味著樹的高度有一個上限,對於紅黑樹,其為2log(n+1),所以時間復雜度為最差為Olog(n)。
賦予二叉搜索樹自平衡特性的方法有多種,紅黑樹通過一下4條約束實現自平衡:
Every node is either red or black.
All NIL nodes (figure 1) are considered black.
A red node does not have a red child.
Everypathfrom a given node to any of its descendant NIL nodes goes through the same number of black nodes.
其中根節點為黑色。
紅黑樹的搜索與二叉搜索樹無異,但是插入和刪除可能會違背上述四條原則。需要用到左旋右旋操作。左旋右旋上圖,可以看到左旋右旋本身不改變二叉搜索樹的特性,旋轉後必要時改變節點的顏色可消除插入或者刪除帶來的紅沖突和黑沖突,有時紅黑樹的重新平衡需要迭代進行。
紅黑樹比較適合的應用場景:
需要動態插入、刪除、查找的場景,包括但不限於:
某些資料庫的增刪改查,比如select * from xxx where 這類條件檢索。
linux內核中進程通過紅黑樹組織管理,便於快速插入、刪除、查找進程的task_struct。
linux內存中內存的管理:分配和回收。用紅黑樹組織已經分配的內存塊,當應用程序調用free釋放內存的時候,可以根據內存地址在紅黑樹中快速找到目標內存塊。
hashmap中(key,value)增、刪、改查的實現;java 8就採用了RBTree替代鏈表。
Ext3文件系統,通過紅黑樹組織目錄項。