自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

從根上理解 Node.js 的 Fs 模塊:一起設計一個文件系統(tǒng)

開發(fā) 前端
Node.js 提供了 File System 的 api,可以讀寫文件、目錄、修改權限、創(chuàng)建軟鏈等。可能大家 api 用的比較熟練,但對于這些 api 的原理不一定理解。要想真正理解 File System,還得從根上來看。

[[424137]]

Node.js 提供了 File System 的 api,可以讀寫文件、目錄、修改權限、創(chuàng)建軟鏈等。

可能大家 api 用的比較熟練,但對于這些 api 的原理不一定理解。要想真正理解 File System,還得從根上來看。

下面我們從 0 到 1 設計一個文件系統(tǒng)試試。

從 0 到 1 設計一個文件系統(tǒng)

什么是文件呢?

[[424138]]

這樣一份比較完整的資料就是文件。

但是計算機的持久化存儲是在硬盤,主要是磁盤和 SSD 固定硬盤:

計算機里的文件是一個邏輯概念,并不是物理上存在的一個個實體。

那么如果給了這樣一個硬盤,讓我們自己造一個文件系統(tǒng)出來,實現(xiàn)文件的功能。怎么做呢?

簡單想了下:挨著放。

然后還要記錄下索引,啥文件在啥位置:

這樣是可以,但是有個問題,萬一文件 B 被刪除了,那對應的空間就要釋放:

然后又來了一個文件 D,發(fā)現(xiàn)放不進去啊,這地方太小了。

A 和 B 中間這塊空間就是碎片,碎片會把磁盤可用空間割裂成不連續(xù)的很多小塊。

怎么辦呢?如何更好的利用磁盤空間?

分塊!把文件分成一小塊一小塊的,比如 1k 為一個塊,可以不用連續(xù)存,把所有塊記錄在索引中就行了。

索引咋記錄的看不清,放大點來看:

每個文件的索引中都記錄了把數(shù)據(jù)存在了哪幾個塊,這樣一塊一塊的讀出來就行了。

而且文件刪除了,那些塊還可以繼續(xù)用,不會有很大的碎片。

妙啊!

難怪文件系統(tǒng)第一步就是分塊,內存管理第一步是分頁,這樣才能高效利用空間啊。

這種索引節(jié)點,可以叫做 index node,簡稱 inode 就好了。

而且,除了文件名和存放的塊以外,還可以記錄其他信息,比如創(chuàng)建時間、修改時間、文件權限、所屬用戶等等。

到這里就可以對文件下個物理層面上的定義了: 文件就是 inode 記錄的信息和它所索引的一系列數(shù)據(jù)塊。

那我寫文件利用了一個塊,刪除文件釋放了一個塊,怎么知道呢?得單獨記錄下來塊的狀態(tài)。

數(shù)據(jù)塊只有空閑和被占用兩個狀態(tài),一個二進制位就行了。通過一段二進制數(shù)把所有塊的空閑狀態(tài)記錄下來。一個位代表一個值,這叫做位圖。在這里就是塊位圖。

硬盤中大部分是數(shù)據(jù)塊,開頭的一段來放 inode 所在的塊和數(shù)據(jù)塊的塊位圖。

inode 也是存在塊里的,比如我們規(guī)定只能用 5 個塊放 inode,那 inode 總量是有限的,也就是是說文件系統(tǒng)可以創(chuàng)建的文件是有上限的。

我們也要記錄下所有 inode 的空閑狀態(tài),也就是 inode 位圖。

簡單理一下我們設計的文件系統(tǒng):

為了更好的利用硬盤空間,我們對數(shù)據(jù)進行了分塊,每個文件用到了哪些塊記錄在 inode 里。inode 還記錄了文件的創(chuàng)建時間、修改時間、權限等信息。

通過塊位圖來記錄數(shù)據(jù)塊空閑狀態(tài),通過 inode 位圖來記錄 inode 的空閑狀態(tài)。

但我如果想知道硬盤中有幾個塊、用了幾個,有幾個 inode、用了幾個,怎么辦呢?

簡單,遍歷一遍塊位圖和 inode 位圖,就知道個數(shù)了。

但每次這么算太慢了,這就像我們設計數(shù)據(jù)庫的時候,一個論壇下面有多少個帖子,這個數(shù)據(jù)不會是每次用 sql 查詢的,而是在帖子增刪的時候動態(tài)維護一個字段在數(shù)據(jù)庫表中,直接查詢即可。

那我們也設計一個塊用來存這種統(tǒng)計信息,也就是:

這個塊是較高層的統(tǒng)計信息,我們可以叫它超級塊。

現(xiàn)在把我們設計好的文件系統(tǒng)交給用戶,就可以通過它來高效利用硬盤了。

發(fā)布版本:神光文件系統(tǒng) V1.0。

但現(xiàn)在我們的文件系統(tǒng)好像還不是很好用,只能創(chuàng)建文件,那如果我創(chuàng)建了 1000 個文件呢?

查詢起來慢,也容易命名沖突。

怎么辦呢?

命名空間!目錄!就像文件夾的思想一樣。

那怎么實現(xiàn)呢?

每個 inode 是一個文件,那把 inode 組織成樹不就行了。

比如我們有兩個文件 B 和 C:

我們創(chuàng)建一個目錄 A:

在 inode 里面添加一個 isDirectory 的屬性,如果是目錄,那么就讀取數(shù)據(jù)塊的內容,找到其中的 inode 節(jié)點編號,就知道該目錄下的文件了。

這就是目錄的實現(xiàn)原理:通過 inode 的 isDirectory 屬性區(qū)分是文件還是目錄,如果是目錄就讀取數(shù)據(jù)塊中的 inode 信息來查找子文件,如果是文件,則直接讀取數(shù)據(jù)塊作為文件內容。

從一個 inode 到另一個 inode 的查找順序叫做路徑(path)。

比如這樣一個文件的 inode 查找順序:

那文件路徑就是 /A/D/dongdong.jpg

這就是文件路徑的本質:文件路徑就是 inode 查找順序

現(xiàn)在我們支持目錄的嵌套了,可以把文件、目錄組織成樹形結構方便管理。

發(fā)布版本:神光文件系統(tǒng) v2.0。

現(xiàn)在一個 inode 只有一條路徑過來,因為是樹嘛,那如果我想兩條路徑都可以找到同一個 inode 呢?

比如 /A/D/dongdong.jpg 可以訪問到該文件:

我想通過 /A/B/dongdong.jpg 也能訪問,怎么辦呢?

直接指過去不就行了。

這樣確實可以有兩條路徑找到同一個文件,這個額外的鏈接我們起名叫做硬鏈接。

但是因為一個節(jié)點有兩個父節(jié)點,就不再是樹了,變成了圖。所以,文件樹這個概念嚴格意義上來說還是存在問題的,可能是個文件圖。

但是我如果想給 dongdong.jpg 換個名字,叫 dongdong2.jpg 呢?

現(xiàn)在都是同一個 inode 節(jié)點,改了就都改了。但我只想改 /A/B 的 path 的文件名,別的不改。

那就再創(chuàng)建個 inode 節(jié)點,用來改名,然后這個 inode 節(jié)點指向 dongdong.jpg。

這種不直接指過去,多了一個 inode 來改名,之后再指過去,這種我們叫做軟鏈接。

為什么叫硬呢?因為改不了,直接指向同一個 inode。

為什么叫軟呢?因為可以改,多了一層 inode 用來改名。

所以我們分別起名硬軟鏈接。

硬鏈接和軟鏈接都是用于多條路徑可以查找到同一個文件的,但是硬鏈接不能單獨改名,軟連接可以。

monorepo 的實現(xiàn)就是基于軟連接的,可以指向同一個目錄 inode,而且還可以起個別名。

實現(xiàn)了軟硬鏈接,可以發(fā)新版本了。

發(fā)布版本:神光文件系統(tǒng) v3.0。

復盤一下我們設計的文件系統(tǒng):

v1.0:

通過數(shù)據(jù)塊來存儲文件內容,提高硬盤利用效率

通過 inode 記錄所用的數(shù)據(jù)塊和文件的創(chuàng)建時間、權限等信息

通過塊位圖記錄數(shù)據(jù)塊的空閑狀態(tài)

通過 inode 位圖記錄 inode 空閑狀態(tài)。

通過超級塊記錄 inode 和數(shù)據(jù)塊的統(tǒng)計信息。

這個版本實現(xiàn)了文件的存取,但是不支持目錄。

v2.0:

通過 inode 中添加一個屬性來記錄是文件還是目錄

目錄的數(shù)據(jù)塊中存放具體文件列表的 inode 信息,讀取目錄的時候可以讀取出文件列表。

按照目錄 inode、文件 inode 的一層層的查找順序叫做文件路徑。

這個版本實現(xiàn)了目錄和路徑的功能。

v3.0:

通過多個目錄 inode 包含同一個 inode 的方式,來實現(xiàn)多條路徑查找同一文件的功能,叫做硬鏈接。

目錄先創(chuàng)建一個 inode 節(jié)點用于改名,然后該 inode 節(jié)點指向目標 inode 節(jié)點,這叫做軟連接。

這個版本實現(xiàn)了多條路徑查找統(tǒng)一文件的軟硬鏈接功能。

真實的文件系統(tǒng)也是類似的實現(xiàn),目前有很多文件系統(tǒng),比如 ext2、FAT 等,原理和我們設計的文件系統(tǒng)差不多。

文件系統(tǒng)設計完了,回到最開始的目標,我們是想深入理解 Node.js 的 File System 的 api。下面就來看一下。

Node.js 的文件系統(tǒng) api

Node.js 通過 V8 注入了 fs 的 api 給 js 用,底層是通過 c++ 調用操作系統(tǒng)的文件系統(tǒng)功能,也就是我們上面設計的那種文件系統(tǒng)。

我們調用的 fs 的 api 最終就是調用了操作系統(tǒng)的文件系統(tǒng)功能。

自己設計了一個文件系統(tǒng)之后,我們再來看下 fs 的 api,是不是理解更深了:

  • fs.stat 獲取 inode 中的信息的
  • fs.chmod 修改文件權限,也是修改 inode 信息
  • fs.chown 修改所屬用戶,也是修改 inode 信息
  • fs.copyFile 復制 inode 和數(shù)據(jù)塊,把新的 inode 添加到對應目錄的 inode 內容中
  • fs.link 創(chuàng)建軟硬鏈接的,也就是多條路徑查找同一個文件的 inode,軟連接還可以改名
  • fs.mkdir 創(chuàng)建目錄 inode 的
  • fs.rmdir 讀取目錄 inode 包含的所有文件 inode 的

具體 api 還有很多,但都是用來操作我們上面設計的那個文件系統(tǒng)的。

從根上理解了文件系統(tǒng),用這些 api 也會得心應手。

總結

為了真正理解 Node.js 的 fs 模塊,我們一起設計了一個文件系統(tǒng):

  • 把文件分成不同數(shù)據(jù)塊,這樣可以高效利用磁盤空間。
  • 文件的索引節(jié)點 index node 中記錄了所包含的數(shù)據(jù)塊和創(chuàng)建時間、權限、是否是目錄等信息。
  • 通過塊位圖記錄數(shù)據(jù)塊空閑狀態(tài)。
  • 通過 inode 位圖記錄 inode 空閑狀態(tài)。
  • 通過超級塊記錄硬盤的 inode、數(shù)據(jù)塊的使用信息。
  • 通過 inode 對應的數(shù)據(jù)塊內容包含文件 inode 信息列表的方式實現(xiàn)了目錄節(jié)點。

我們得出一些重要結論:

文件本質上就是 inode + 數(shù)據(jù)塊。

路徑本質上就是查找目標 inode 的路徑。

硬鏈接本質上就是多個目錄 inode 包含同一個 inode。

軟連接本質上就是多創(chuàng)建了一個 inode 用于改名,對應數(shù)據(jù)塊中指向目標 inode。

Node.js 的 fs api 是通過 c++ 注入 v8 的對操作系統(tǒng)能力的調用,理解了文件系統(tǒng),再學那些 api 就很輕松了。

 

責任編輯:武曉燕 來源: 神光的編程秘籍
相關推薦

2022-04-07 09:29:04

文件系統(tǒng)硬盤操作系統(tǒng)

2021-10-12 23:45:43

NodeJs事件

2023-06-20 06:44:14

Node.jsCPU 負載

2020-11-05 09:27:48

JavaScript開發(fā)技術

2024-06-17 11:59:39

2011-10-25 09:28:30

Node.js

2013-11-01 09:34:56

Node.js技術

2024-03-26 10:38:47

模塊CommonJSES

2022-10-18 18:43:40

Node.js低代碼

2020-08-07 10:40:56

Node.jsexpress前端

2020-08-24 08:07:32

Node.js文件函數(shù)

2019-12-17 11:40:44

Node.js模塊前端

2024-03-11 10:30:31

Linux文件系統(tǒng)

2024-02-28 08:47:29

文件系統(tǒng)數(shù)據(jù)

2022-08-29 07:48:27

文件數(shù)據(jù)參數(shù)類型

2011-06-17 10:29:04

Nodejavascript

2022-06-05 13:52:32

Node.jsDNS 的原理DNS 服務器

2021-09-26 05:06:04

Node.js模塊機制

2024-09-10 08:06:41

2025-03-18 07:40:00

3FSAIDeepSeek
點贊
收藏

51CTO技術棧公眾號