Linux 基础I/O :文件描述符,重定向,文件系统,软链接和硬链接,动态库和静态库
- 文件描述符
- 重定向
- 文件系統(tǒng)
- 軟鏈接和硬鏈接
- 動態(tài)庫和靜態(tài)庫
文件描述符
上面兩個接口分別是c語言的fread接口和linux的read接口,當我們在使用的時,可能會有疑問,為什么linux的io接口能只通過一個整型的fd來操控文件和io?這個fd又是什么?
文件描述符fd
大家應該聽說過,linux下一切皆文件
task_struct也就是pcb在Linux下的實現(xiàn),然后其中的*files指針,就指向了一個文件描述表,表包含的數(shù)組fd_array[]中的每一個就是一個文件指針file *,所以這個fd,就是這個數(shù)組中的一個下標,通過這個下標來找到對應位置的文件指針。
fd:fd是一個文件描述符,是文件的操作句柄,同時是fd_array[]的下標,通過這個下標來找到對應文件的文件指針。
同時,我們創(chuàng)建文件時這個下標是從3開始的,因為0,1,2分別對應stdin(標準輸入),stdout(標準輸出),stderror(標準錯誤)
重定向
通過替換文件描述符,使得數(shù)據(jù)不再寫入原來的文件,而寫入新的文件
常見的重定向符號:
> 重定向輸出符號,覆蓋原來的內(nèi)容并寫入
>>重定向輸出符號,追加寫入
通過 > 符號將原本寫入到標準輸出的數(shù)據(jù)寫入到test1.txt
dup2
int dup2(int oldfd, int newfd)
改變數(shù)據(jù)的流向,使流向newfd的數(shù)據(jù)全都流向到oldfd中。
重定向前,若newfd已經(jīng)有打開的文件,則會關(guān)閉
重定向后,oldfd和newfd都會操作oldfd所操作的文件
首先向標準輸出輸出一個hello(需要\n刷新緩沖區(qū),不刷新的話數(shù)據(jù)會先寫入緩沖區(qū),直到程序結(jié)束才寫入文件)
然后將標準輸出重定向至test.txt文件中
再輸出一個world
這是hello輸出到了標準輸出中,world輸出到了文件中。
文件系統(tǒng)
這里以Linux下的ext2文件系統(tǒng)為例
文件系統(tǒng)就是磁盤上管理文件的系統(tǒng)
每一個分區(qū)都有自己的文件系統(tǒng)。
- bitmap(位圖):一串二進制比特位,用于標記該位置是否存有數(shù)據(jù),1為有,0為無。
- 超級塊:描述文件系統(tǒng),例如有多少磁盤塊,有多少使用
- inode: 文件的元信息,例如大小,屬性,所占的磁盤塊地址
- data : 文件的數(shù)據(jù)
- 目錄項:文件名 + inode節(jié)點號
文件存儲的流程:
通過超級塊來找到數(shù)據(jù)塊位圖和inode位圖,然后通過數(shù)據(jù)塊位圖和inode位圖來找到空閑的數(shù)據(jù)塊和inode節(jié)點,將文件數(shù)據(jù)存入數(shù)據(jù)塊中,將文件元信息存入inode節(jié)點。數(shù)據(jù)存儲完后,還會在當前目錄下,記錄這個文件名稱以及inode節(jié)點號(目錄項)
文件獲取的流程:
通過文件名到父目錄文件中找到對應的目錄項,獲取目錄項中的inode節(jié)點號,通過超級塊來找到對應的inode節(jié)點,再通過inode節(jié)點中文件存儲的數(shù)據(jù)塊的地址來訪問文件數(shù)據(jù)
軟鏈接和硬鏈接
硬鏈接:
本質(zhì)上和源文件沒什么不同,和源文件共享同一個inode節(jié)點,通過這個inode節(jié)點來訪問文件數(shù)據(jù)
創(chuàng)建方法:ln [源文件] [鏈接文件.hard]
軟鏈接(符號鏈接):
本質(zhì)上是一個獨立的文件,有自己的inode節(jié)點,文件數(shù)據(jù)中保存源文件的路徑,通過這個路徑來訪問源文件
創(chuàng)建方法:ln -s [源文件][鏈接文件.soft]
創(chuàng)建test.txt的硬鏈接和軟鏈接
可以通過鏈接文件訪問數(shù)據(jù)。
刪除源文件后硬鏈接還可以訪問源文件數(shù)據(jù),軟鏈接失效。
原因:硬鏈接與源文件共用同一個inode,刪除源文件后只是減少了inode的一個鏈接數(shù),硬鏈接文件還可以繼續(xù)訪問源文件數(shù)據(jù)。而軟鏈接是通過源文件路徑來訪問數(shù)據(jù),但是源文件已經(jīng)刪除,所以路徑訪問不到,無法獲取源文件數(shù)據(jù)。
同時需要注意的是,刪除一個文件,文件并不會立即刪除,而是先刪除了目錄項中的文件名信息,并使inode的鏈接數(shù)減一,只有鏈接數(shù)為0時文件才會刪除。
跨分區(qū)
因為每一個分區(qū)都有自己獨立的文件系統(tǒng),也就是說有自己的一套inode節(jié)點,所以硬鏈接是無法跨分區(qū)的,因為操作系統(tǒng)會無法識別這個inode到底是哪一個分區(qū)的,而使用路徑訪問的軟鏈接則可以跨分區(qū)。
同時,硬鏈接也無法對目錄鏈接,因為目錄本身也是跨分區(qū)的。
動態(tài)庫和靜態(tài)庫
庫文件:打包了一堆實現(xiàn)了常用功能的代碼文件。
當我們在調(diào)用庫函數(shù)和系統(tǒng)函數(shù)的時候,例如stdio.h中的printf,我們并沒有定義對函數(shù)的實現(xiàn),那么是在哪里實現(xiàn)的呢?
系統(tǒng)把這些函數(shù)的實現(xiàn)放到了/usr/lib下的庫文件中,如果沒有指定時,編譯器會自動到系統(tǒng)默認的庫函數(shù)搜索路徑下面進行查找,然后在鏈接階段將庫鏈接進代碼中。
函數(shù)庫分為靜態(tài)庫和動態(tài)庫兩種。
靜態(tài)庫
靜態(tài)庫的加載是在編譯鏈接時將庫函數(shù)的代碼全部加入到可執(zhí)行文件中,雖然生成的文件比較大,但是運行的使用也不需要庫文件了。
生成靜態(tài)庫方法:
gcc -c *****.c -o *****.o 先將.c文件預處理、編譯、匯編
ar -cr lib*****.a *****.o (靜態(tài)庫命名:lib**.a)將.o文件封裝成庫函數(shù)**
鏈接靜態(tài)庫方法:
1.將庫文件移動到指定路徑下:/usr/lib64 /usr/lib
2.通過環(huán)境變量指定庫的所在路徑:LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
3.通過gcc -L現(xiàn)象指定庫所在路徑
gcc test.c -o test -L. -l******(庫名)
動態(tài)庫
動態(tài)庫在編譯鏈接階段并沒有把代碼加入到可執(zhí)行程序中,而是在程序運行的時候鏈接加載文件庫,節(jié)約了系統(tǒng)的開銷(Linux默認使用動態(tài)庫)
生成動態(tài)庫方法:
gcc -c -fPIC *****.c -o *****.o 先將.c文件預處理、編譯、匯編
gcc -shared -o *****.o lib*****.so (靜態(tài)庫命名:lib**.so)將.o文件封裝成庫函數(shù)**
鏈接動態(tài)庫方法:
1.將庫文件移動到指定路徑下:/usr/lib64 /usr/lib
2.通過環(huán)境變量指定庫的所在路徑:LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
總結(jié)
以上是生活随笔為你收集整理的Linux 基础I/O :文件描述符,重定向,文件系统,软链接和硬链接,动态库和静态库的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux 进程控制 :进程创建,进程终
- 下一篇: Linux 进程间通信:管道、共享内存、