前言
在之前學習當中,我們了解了被打開的文件是如何管理的;磁盤,以及ext2
文件系統是如何存儲文件的。
那我們要打開一個文件,首先要先找到這個文件,操作系統又是如何去查找的呢?
理解操作系統搜索文件
1. 目錄和文件名
我們知道:
- 文件名是不作為文件屬性存儲在文件
inode
里的; - 在一個分區中,根據文件的
inode
值就可以找到該文件。
但是在之前的文件操作時,一種都是使用文件名進行對文件的相關操作,沒有使用過文件inode
值;
還用目錄它是文件嗎?
通過查看我們可以發現目錄也是存在inode
值的,那也就是說目錄也是也文件;
文件 = 屬性 + 內容,那目錄的文件內容是什么呢?
首先屬性不用多說;
目錄文件的文件內容保存的是:文件名和
inode
號的映射關系。
- 所以,訪問文件時,必須打開當前工作目錄,根據文件名獲取對應的
inode
號,然后進行文件訪問。 - 所以,訪問文件必須知道當前工作目錄,本質就是必須打開當前工作目錄文件,查看目錄文件的內容獲取要訪問文件的
inode
號。
2. 路徑解析
知道了訪問當前工作目錄下文件,要打開當前目錄文件,查看當前目錄文件內容;
那要打開當前工作目錄,就要獲取當前工作目錄文件的inode
號啊,如何獲得呢?
很簡單,打開上級目錄,查看上級目錄文件內容;那上級目錄也是文件啊,要打開它也要知道它的inode
號,那也要打開它的上級目錄啊?
所以就一直訪問上級目錄,直到/
根目錄。
所以說:實際上,任何文件都存在路徑;
比如:
/home/lxb/linux/lesson8/code.c
這都要從根目錄開始一次打開每一個目錄文件,依次訪問每個目錄下的指定目錄直到
test.c
文件(這個過程稱之為Linux
路徑解析)
我們知道,訪問文件本質就是進程去訪問,在進程當中存在CWD
當前工作路徑;在我們open
打卡指定文件時也給定了文件的路徑。
所以我們訪問文件必須要有目錄+文件名(絕對路徑)
3. 路徑緩存
我們知道,文件都是在磁盤中存著的,那在Linux
系統中存在真正的目錄嗎?
顯而易見是不存在,只有文件;保存文件屬性+內容。
在上述中,我們還了解到訪問一個文件,都要從根目錄/
開始進行路徑解析?
按道理來說是的,但是太慢了,在
Linux
系統中會緩沖歷史路徑結構。
在Linux
系統中,不存在目錄,那在Linux
系統中我們為什么可以看到目錄路徑結構?
打開的文件如果是目錄,在系統中就在自己的內存中進行路徑維護。
在Linux
系統中,內核里維護樹狀路徑結構的內核結構體叫做:struct dentry
struct dentry {atomic_t d_count;unsigned int d_flags; /* protected by d_lock */spinlock_t d_lock; /* per dentry lock */struct inode *d_inode; /* Where the name belongs to - NULL is* negative *//*The next three fields are touched by __d_lookup. Place them hereso they all fit in a cache line.*/struct hlist_node d_hash; /* lookup hash list */struct dentry *d_parent; /* parent directory */struct qstr d_name;struct list_head d_lru; /* LRU list *//*d_child and d_rcu can share memory*/union {struct list_head d_child; /* child of parent list */struct rcu_head d_rcu;} d_u;struct list_head d_subdirs; /* our children */struct list_head d_alias; /* inode alias list */unsigned long d_time; /* used by d_revalidate */struct dentry_operations *d_op;struct super_block *d_sb; /* The root of the dentry tree */void *d_fsdata; /* fs-specific data */
#ifdef CONFIG_PROFILINGstruct dcookie_struct *d_cookie; /* cookie, if any */
#endifint d_mounted;unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */
};
- 每一個文件其實都有對應的
dentry
結構,包含普通文件;所以被打開的文件,在內存中就可以形成樹狀結構。- 整個樹形節點也會同時屬于
LRU
(Least Recently Used),在最近最少使用結構在,進行節點淘汰。- 同時也會屬于
Hash
表,方便快速查找。- 這樣有了樹狀結構,整體就有了
Linux
路徑緩存結構,打開和訪問任何文件,都先在該樹下進行查找,找到了就返回inode
和內容,沒找到就從磁盤加載路徑,添加到dentry
結構中。
4. 掛載分區
在之前的描述中,都是在一個文件系統中,根據inode
號查找文件,那inode
號又不是跨分區的,如何根據inode
確定是哪一個分區呢?
在分區寫入文件系統后,我們沒有辦法直接使用;我們需要將文件系統與指定的目錄進行關聯(也就是掛載)才能使用
所以就可以根據我們訪問目標文件的路徑前綴來判斷文件在哪一個分區。
這里關于掛載的相關操作,就不演示了;可以自己嘗試一下。
軟硬鏈接
1. 軟鏈接
在Windows
中,我們可以給一個文件創建快捷方式,然后放到桌面,這樣打開桌面的快捷方式就是打開文件了;
而在Linux
系統中,我們也可以給文件創建快捷方式——就是軟鏈接
ln -s code code.c
創建軟鏈接文件code
指向文件code.c
;(可以說code
文件是code.c
的快捷方式)
軟鏈接是一個獨立的文件
2. 硬鏈接
我們直到一個目錄中,存在.
和..
兩個隱藏文件,.
指向當前目錄,..
指向上級目錄;
那也就是說,這些文件名都對應一個inode
值。
這里.
和..
就是典型的硬鏈接。
而在內核中,記錄了連接數:
創建硬鏈接:
ln 已存在文件 硬鏈接文件
這里要注意,我們只能給文件創建硬鏈接,不能給目錄創建硬鏈接。
這里可能會感覺很奇怪,
.
和..
不就是給目錄創建硬鏈接嗎?我們為什么不能創建?這里還是為了避免循環路徑問題,在內核中在路徑搜索時,對
.
和..
做了特殊處理,所以.
和..
不會造成循環路徑問題;而軟鏈接,它是一個獨立的文件,在路徑遍歷時不會把他當做目錄文件來處理。
如果我們自己創建硬鏈接,就有可能造成循環路徑問題。
3. 軟硬鏈接的區別
- 軟鏈接是一個獨立的文件
- 硬鏈接只是文件名和目標文件的一組映射關系
4. 軟硬鏈接的作用
- 軟鏈接就類似于快捷方式
- 硬鏈接
.
和..
,方便用戶進程操作;文件備份。
到這里本篇文章內容就結束了,感謝各位大佬的支持