一、沒有被打開的文件
如果一個文件沒有被打開,那么該文件存儲在哪里?
該文件是存儲在磁盤當中的!
文件 = 文件內容 + 文件屬性!
- 文件的內容是按照數據塊存儲的;
- 文件的屬性其實就是inode(是一個128字節的數據塊,包含該文件的所有屬性);
- Linux的文件在磁盤中存儲,是將文件的內容和屬性分開存儲的!!!
磁盤的特性:
- 磁頭是一面一個;
- 磁頭和盤面不接觸(挨得非常近);
- 磁盤一般處于無塵環境;(灰塵對磁盤的影響很大!)
- 數據是在盤面中存儲的;
- 磁盤是永久性存儲介質(無電沒影響);
如上圖所示:綠色的是磁道,紅色的是扇區;
磁盤中,一圈同心圓被稱為磁道,磁道會被且為一小段一小段的區域,這一小段區域被稱為扇區!磁盤會被分為無數個扇區;
磁盤被訪問的最基本單元是扇區;一個扇區大小通常是512字節,甚至有4KB;
我們可以把磁盤看作是無數個扇區構成的存儲介質;
要把數據存儲到磁盤,第一個要解決的問題就是定位一個扇區!
因此,首先我們要先定位到哪個面,即定位用哪個磁頭?
接下來我們要確定訪問哪個磁道?然后再定位訪問哪一個扇區?
同一磁道,從上面往下看就是柱面的概念!
磁頭是同時移動的!
假如說當前三面磁盤六個磁頭,磁頭要移動的時候六個磁頭同時動!
磁頭的左右擺動實際上是定位磁道和柱面的過程!(確定當前半徑即磁道大小!)
當磁頭不動,光盤動的時候,該過程被稱為定位扇區!
對磁盤來說:
- 運動越少,效率越高;
- 運動越多,效率越低;
對于磁盤尋址,有三個關鍵的參數:Cylinder(柱面),Header(磁頭),Sector(磁道)三個參數;
根據這三個參數確定的扇區地址被稱為CHS尋址法則;
如果當前我們有三個磁盤,一共六面;
我們將其延展開,邏輯上可以看作是線性的!
其中,每一面又包括許多磁道!每一個磁道又包括多個扇形;
那么最終我們可以得到以扇區為基本單位的數組:(任何一個扇區都有對應的下標)
但是磁盤確認只根據CHS,因此此時我們需要找到對應的CHS和我們抽象化的數組之間的關系!
假設當前磁盤一個盤面有2w個扇區,每個扇區有50個磁道,而每個磁道有400個扇區!
當前有一個扇區標號為28888;那么此時我們根據對應的邏輯運算可以反推得到該扇區位于哪個磁面,哪個磁道和扇區!
LBA地址即為我們抽象的邏輯地址!
回歸到磁盤的硬件?
不僅CPU有寄存器,其他外設(磁盤)也有寄存器!
磁盤當中有三個寄存器:
- 控制寄存器;
- 數據寄存器;
- 狀態寄存器;
如果操作系統想要訪問磁盤,此時需要告訴控制寄存器當前是讀取還是寫入?即控制寄存器控制IO方向(r/w),然后讀取/寫入的數據位于數據寄存器當中,接下來再獲取LBA的地址即可進行讀取或寫入,最后返回操作后的結果;
文件系統
假設當前我們有800G的磁盤空間,分區的過程實際上就是定義一個結構體,該結構體包含了抽象數組中我們使用的起始地址和最終地址!
此時我們只需要把這分割好的200G管理好,那么按照相同的策略即可管理好總的800G的磁盤!
我們先看Data block:
Data blocks可以有很多塊(block),每個block的大小可以是1024,2048,4096個字節,這三種選項;Data blocks是用于存放文件內容的;(此時凡是我們通過fopen,fread,fwrite訪問磁盤,那么訪問的基本單元都是上面三種我們設置的1,2,4KB大小(文件塊大小)!一般而言,每個塊只有自己對應的數據!)
inode table:存放的有單個文件的所有屬性,一般的大小是128字節!一般而言,一個文件有一個inode!在inode里面有唯一的編號!且該文件內容有多少個塊(block)這一信息也在inode!
inode可能大致如下結構所示:
inode不包含文件的名稱!每個文件用唯一編號確認!
通過ls -li可以查看文件對應的編號:
在Linux系統里面標識一個文件使用的是inode編號!
?
假如說當前NUM = 15,那么是不是說該文件最大為4*15 = 60KB呢?
答案:不是!可以通過二級索引以上來進行擴容!
例如當前我們0~12為直接索引,直接指向文件內容;12,13,14可是是二級索引,引用的塊用于存放新的數據塊的指針!4KB = 4*1024;每個二級索引最大為4MB!?
1. 直接索引(Direct Index)
- 定義:?inode中的
block[0]
到block[11]
(不同文件系統數量可能不同)是直接索引項,每個項直接指向一個數據塊(Data Block)。例如,若直接索引項有12個,每個數據塊大小為4KB,則直接索引可存儲最大?12 × 4KB = 48KB?的文件。 - 作用:?直接處理小文件,無需額外索引塊,訪問速度快。
- 示例:?若文件僅占用直接索引塊,系統直接通過
block[i]
找到對應數據塊。
2. 二級索引(一級間接索引,Indirect Index)
- 定義:?inode中某個索引項(如
block[12]
)指向一個一級間接索引塊,該索引塊本身存儲多個數據塊指針。假設每個指針占用4字節,一個4KB的索引塊可存儲?4096B / 4B = 1024個指針。此時,二級索引可支持?1024 × 4KB = 4MB?的數據。 - 作用:?擴展中等大小文件的存儲能力,避免直接索引項不足。
- 流程:
- inode的
block[12]
指向一個索引塊。 - 索引塊中的每個指針指向實際數據塊。
- 系統通過兩次磁盤訪問(索引塊 + 數據塊)獲取數據 。
?
- inode的
3. 三級索引(二級間接索引,Double Indirect Index)
- 定義:?inode中某個索引項(如
block[13]
)指向一個二級間接索引塊,該索引塊再指向多個一級間接索引塊,每個一級索引塊再指向數據塊。此時,三級索引可支持?1024 × 1024 × 4KB = 4GB?的數據。 - 作用:?支持大文件,通過多層間接索引擴展存儲容量。
- 流程:
- inode的
block[13]
指向二級間接索引塊。 - 二級索引塊中的指針指向多個一級間接索引塊。
- 每個一級索引塊再指向數據塊。
- 系統需三次磁盤訪問(二級索引塊 + 一級索引塊 + 數據塊) 。
?
- inode的
我們如何知道哪個存放文件的數據塊被使用了,哪個沒有被使用?
Block Bitmap:?Block Bitmap里面存放了記錄Data Block中的哪個數據塊被占用了,哪個數據塊沒被占用!(1個比特位表示1個塊! --- 置為1表示該塊被使用!)
4KB = 4096個字節 = 4096*4個比特位!
問題:刪一個文件的時候,用不用把塊(文件內容)清空呢?
不用!只需要將對應的位圖清空!全設置為0即可!
- 獲取當前文件的inode編號(在inode table里面)
- 然后再inode bitmap查看該inode是否是有效的!
- 如果有效,在通過inode table讀取屬性,獲得inode編號與其內容的映射關系,將讀取到的塊號在block bitmap里面置為0!
- 再在inode bitmap將對應的編號設置為0!
刪文件對內容沒有關系!
每一個文件的分組都有如上的結構;
在Linux中,inode編號是以分區為單位統一分配的(不能跨分區)!?
磁盤訪問中是以塊大小為基本單位的!扇區是最小單位!(例如8個扇區的大小即為1個塊!)
- 一共有多少個組;
- 每個組的大小
- 每個組的inode的大小;
- 每個組的block的數量;
- 每個組的其實inode;
- 文件系統的類型和名稱等!
super block不會在每一個組中都有!有的組可能沒有,有的組可能有多份!
如果當前super block這個模塊的內容掛掉了!那么當前根據組進行的分區等什么都做不了,因此整個分區都掛掉了!
所以一般會在Block group 0 ~ n中零零散散有多個Super block!
結論:每一個分區在被使用前,都需要提前將部分文件系統的屬性信息提前設置進對應的分區當中!方便我們后續使用這個分區或者分組,這一過程叫做格式化!(具體點還會將Block Bitmap 和 inode Bitmap進行清空!再將對應的文件信息寫入進去)
藍色部分是為了管理后面紅色部分的屬性信息!
在Linux中,可以通過stat指令查看文件的詳細信息(比ls更詳細)
問題:
- 新建一個文件,系統要做什么?
- 刪除一個文件,系統要做什么?
- 查找一個文件,系統要做什么?
- 修改一個文件,系統要做什么?
回答上面這些問題之前,我們可以先總結下我們得到的結論:
- Linux中,一個文件只有一個對應的inode,每一個inode都有自己對應的inode編號!(inode的設置只在對應的分區有效,例如我們舉例的200G)
- inode表示文件的所有屬性,文件名并不屬于文件屬性!
當我們在一個路徑下創建文件,有了路徑我們可以確定要創建到對應的那個分區!
系統會對當前的文件分配對應的inode編號(分配inode編號的過程,根據路徑我們已經認定是在哪個區了,然后查詢對應的GDT,可以發現對應的inode的使用率很低,然后再查詢inode bitmap,查詢到最近的沒有被使用的inode編號,然后分配)
刪除 = 允許被覆蓋!
cat test.txt
在操作系統的層面上看:實際上是cat根據test.txt的inode找到對應的磁盤分區和分組,然后在inode BitMap確定該文件對應的inode是0還是1,如果是1,再到inode Table查詢對應的存儲空間(blocks),然后讀取對應的數據塊的內容;
stat test.txt
在操作系統的層面上看:實際上是stat也是根據文件的inode找到對應的inode table,再將里面的重要的屬性提取出來!
問題:我們如何知道一個文件的inode編號?
用戶從來沒有關心過inode,用的是文件名!
解答:這是因為目錄也是文件!也有自己對應的inode編號;
我們知道,文件 = 內容 + 屬性,那么目錄的內容是什么?即目錄需不需要對應的數據塊?
答案是需要的!在目錄的數據塊里面,存放了文件的文件名和對應的inode的映射關系!
問題:當我們執行ls /ll 的時候,對于磁盤文件操作系統應該是如何實現的?
找到當前目錄文件的inode,然后根據inode再對應的inode table找到對應的數據塊,此時可以找到文件名和對應文件的映射關系!此時可以找到目錄里面文件的inode,從而對接到上面新建文件等四個過程!
因此接下來我們可以回答之前的四個問題:
- 為什么同一個目錄不能用同名文件?
文件名作為key值要找到對應的inode編號,即value!
- 為什么目錄下,沒有w我們不能創建文件?
即使能將文件創建出來,但是這個文件的文件名和inode的映射關系無法寫入到數據塊中!
- 為什么目錄下,沒有r我們不能查看文件?
查看文件之前,我們需要獲取文件的inode,但是當前目錄我們無法讀取數據塊中的內容!因此無法查看文件!
- 為什么目錄下,沒有x我們不能進入目錄?
進入一個目錄需要cd,cd的本質實際上就是找到目錄的inode,然后把當前系統的環境變量進行更新!但是當前我們無法獲取inode!
- 路徑解析的必要條件:?當用戶嘗試進入目錄(如執行
cd dir
)或訪問目錄內的文件(如cat dir/file
),系統需要遍歷目錄的目錄項以找到目標文件的inode號。這一過程需要訪問目錄的數據塊,而訪問數據塊的前提是目錄具備x權限?。 - x權限與inode的關系:?目錄的x權限控制了對目錄數據塊的搜索能力。即使有讀權限(r),也只能列出文件名(通過
ls
),但無法通過inode號訪問具體文件,因為系統無法定位到目錄數據塊的物理位置 。
關鍵問題:怎么獲取目錄的inode編號?
我們需要從當前目錄進行遞歸向上尋找,直到找到根目錄,根目錄里面存放的有目錄的inode信息!訪問任何的文件,我們都需要路徑來進行訪問!
二、軟硬鏈接
軟鏈接是一個獨立的文件!因為具有獨立的inode!
建立硬鏈接的指令:
ln 原文件 硬鏈接名字
# 例如:ln cat.jpg my_pet.jpg
?建立軟鏈接的指令:
ln -s 原文件 軟鏈接名字
# 例如:ln -s cat.jpg shortcut_to_cat.jpg
- ln是建立鏈接的指令!
- -s表示建立軟鏈接;
- ln什么都不帶表示表示硬鏈接!
針對硬鏈接:?
對于硬鏈接,我們發現文件和硬鏈接共用一個inode!
硬鏈接不是獨立的文件,因為沒有獨立的inode!
硬鏈接形成的inode一樣,所以對應的文件的特性是一樣的!
結論:所謂的建立硬鏈接,本質其實就是在特定目錄的數據塊中新增文件名和指向的文件的inode的映射關系!
- 硬鏈接的本質實際上就是取別名!
- 任意的一個文件,無論是目錄還是普通文件,都有inode編號!
- 在每一個inode編號的內部,都有一個引用計數的計數器!(計數器的作用是表明當前有多少個文件指向這個inode)
可以存在多個文件名映射同一個inode!
引用計數為0的時候,該文件才會被徹底刪除!
針對軟鏈接:?
如何理解軟連接?
軟連接是一個獨立的文件,有獨立的inode編號,也有獨立的數據塊,它的數據塊里面存放的是指向原文件的路徑!
因此,當我們進入如下操作的時候:
我們往源文件中寫入數據,軟鏈接的文件也能直接訪問到(因為寫入的是地址)!?
因此,如果將軟鏈接刪除,對源文件無影響;
但是如果將源文件進行刪除,軟鏈接就找不到了!
軟連接類似于Windows中的快捷方式!
除了通過rm進行刪除,我們還可以進行unlink進行刪除!(軟硬鏈接都可以!)
unlink 軟/硬鏈接文件名
軟鏈接的應用:
當我們需要執行的程序位于路徑深處,但是此時我們想要在當前目錄下運行,此時我們可以跟其進行軟連接,而不用到路徑深處來執行!
例如下面的例子:
硬鏈接的應用:
當前目錄下我們有一個file文件,其硬鏈接數為1很好理解;
但是如果我們創建一個空目錄,那么當前的硬鏈接數為2!
這是因為當我們進入到這個目錄的時候,我們還有對應的一個點也就是當前目錄!?
一個點是對應的文件夾的硬鏈接,所以它們的inode值是一樣的!?
問題:為什么對應的..的硬鏈接數是3呢?
這是因為..(上級目錄)是一個對應的硬鏈接,然后上一級目錄是lesson22,這個目錄還存在本身和當前目錄.? !!!
如果我們子啊對應的dir目錄下再創建一個子目錄,這時候dir對應的硬鏈接會變為3!
這是因為創建的子目錄里面包含了對應的..上級目錄,這算一個硬鏈接!
規律:已知當前目錄的硬鏈接數,那么這個目錄下有多少個子目錄呢?(硬鏈接數 -2)
應用:通常用于路徑定位,采用硬鏈接可以進行路徑間的切換!
問題:Linux內部不允許對目錄進行硬鏈接,為什么?
如果我們要在根目錄下根據文件名查找一個文件且此時與根目錄實現硬鏈接:
此時我們需要讀取路徑上inode和其對應的屬性,但是當我們找到硬鏈接的時候,此時又重新返回到根目錄,造成死循環!
問題:目錄內部有 ./..不是硬鏈接嗎?
這是操作系統自己編碼時實現的,操作系統可以,但是用戶不可以,哪怕是root!
系統在搜索路徑的時候,不會對.和..這兩個硬鏈接的路徑做搜索!所以不會出現死循環!
硬鏈接只是對應的文件名和一對對應的inode映射!不是真正的目錄,依舊屬于當前目錄下的內容,因此rm刪除目錄不需要考慮.和..!