檔案描述符和檔案指標的區別
2011-07-05 16:05:52
分類: linux
檔案描述符:在linux系統中開啟檔案就會獲得檔案描述符,它是個很小的正整數。每個程序在pcb(process control block)中儲存著乙份檔案描述符表,檔案描述符就是這個表的索引,每個表項都有乙個指向已開啟檔案的指標。
檔案指標:c語言中使用檔案指標做為i/o的控制代碼。檔案指標指向程序使用者區中的乙個被稱為file結構的資料結構。file結構包括乙個緩衝區和乙個檔案描述符。而檔案描述符是檔案描述符表的乙個索引,因此從某種意義上說檔案指標就是控制代碼的控制代碼(在windows系統上,檔案描述符被稱作檔案控制代碼)。
附:檔案系統
vfs
linux支援各種各樣的檔案系統格式,如ext2、ext3、reiserfs、fat、ntfs、iso9660等等,不同的磁碟分割槽、光碟或其它儲存裝置都有不同的檔案系統格式,然而這些檔案系統都可以mount到某個目錄下,使我們看到乙個統一的目錄樹,各種檔案系統上的目錄和檔案我們用ls命令看起來是一樣的,讀寫操作用起來也都是一樣的,這是怎麼做到的呢?linux核心在各種不同的檔案系統格式之上做了乙個抽象層,使得檔案、目錄、讀寫訪問等概念成為抽象層的概念,因此各種檔案系統看起來用起來都一樣,這個抽象層稱為虛擬檔案系統(vfs,virtual filesystem)。上一節我們介紹了一種典型的檔案
系統在磁碟上的儲存布局,這一節我們介紹執行時檔案系統在核心中的表示。
核心資料結構
linux核心的vfs子系統可以圖示如下:
在第 28 章 檔案與i/o
中講過,每個程序在pcb(process control block)中都儲存著乙份檔案描述符表,檔案描述符就是這個表的索引,每個表項都有乙個指向已開啟檔案的指標,現在我們明確一下:已開啟的檔案在核心中用file結構體表示,檔案描述符表中的指標指向file結構體。
在file結構體中維護file status flag(file結構體的成員f_flags)和當前讀寫位置(file結構體的成員f_pos)。在上圖中,程序1和程序2都開啟同一檔案,但是對應不同的file結構體,因此可以有不同的file status flag和讀寫位置。file結構體中比較重要的成員還有f_count,表示引用計數(reference count),後面我們會講到,dup、fork等系統呼叫會導致多個檔案描述符指向同乙個file結構體,例如有fd1和fd2都引用同乙個file結構體,那麼它的引用計數就是2,當close(fd1)時並不會釋放file結構體,而只是把引用計數減到1,如果再close(fd2),引用計數就會減到0同時釋放file結構體,這才真的關閉了檔案。
每個file結構體都指向乙個file_operations結構體,這個結構體的成員都是函式指標,指向實現各種檔案操作的核心函式。比如在使用者程式中read乙個檔案描述符,read通過系統呼叫進入核心,然後找到這個檔案描述符所指向的file結構體,找到file結構體所指向的file_operations結構體,呼叫它的read成員所指向的核心函式以完成使用者請求。在使用者程式中呼叫lseek、read、write、ioctl、open等函式,最終都由核心呼叫file_operations的各成員所指向的核心函式完成使用者請求。file_operations結構體中的release成員用於完成使用者程式的close請求,之所以叫release而不叫close是因為它不一定真的關閉檔案,而是減少引用計數,只有引用計數減到0才關閉檔案。對於同乙個檔案系統上開啟的常規檔案來說,read、write等檔案操作的步驟和方法應該是一樣的,呼叫的函式應該是相同的,所以圖中的三個開啟檔案的file結構體指向同乙個file_operations結構體。如果開啟乙個字元裝置檔案,那麼它的read、write操作肯定和常規檔案不一樣,不是讀寫磁碟的資料塊而是讀寫硬體裝置,所以file結構體應該指向不同的file_operations結構體,其中的各種檔案操作函式由該裝置的驅動程式實現。
每個file結構體都有乙個指向dentry結構體的指標,「dentry」是directory entry(目錄項)的縮寫。我們傳給open、stat等函式的引數的是乙個路徑,例如/home/akaedu/a,需要根據路徑找到檔案的inode。為了減少讀盤次數,核心快取了目錄的樹狀結構,稱為dentry cache,其中每個節點是乙個dentry結構體,只要沿著路徑各部分的dentry搜尋即可,從根目錄/找到home目錄,然後找到akaedu目錄,然後找到檔案a。dentry cache只儲存最近訪問過的目錄項,如果要找的目錄項在cache中沒有,就要從磁碟讀到記憶體中。
每個dentry結構體都有乙個指標指向inode結構體。inode結構體儲存著從磁碟inode讀上來的資訊。在上圖的例子中,有兩個dentry,分別表示/home/akaedu/a和/home/akaedu/b,它們都指向同乙個inode,說明這兩個檔案互為硬鏈結。
硬連線不能跨分割槽,而軟連線可以!
硬連線總是指向乙個i節點,而軟連線是建立乙個新的i節點。這就是它為什麼可以跨分割槽的原因!
軟連線可以對乙個不存在的檔案鏈結,而硬連線不能,因為他要指向原始檔的i節點,所以原始檔必須存在!硬連線不能對目錄鏈結,i節點的原因是其中之一,第二個原因是目錄的特殊性!inode結構體中儲存著從磁碟分割槽的inode讀上來資訊,例如所有者、檔案大小、檔案型別和許可權位等。每個inode結構體都有乙個指向inode_operations結構體的指標,後者也是一組函式指標指向一些完成檔案目錄操作的核心函式。和file_operations不同,inode_operations所指向的不是針對某乙個檔案進行操作的函式,而是影響檔案和目錄布局的函式,例如新增刪除檔案和目錄、跟蹤符號鏈結等等,屬於同一檔案系統的各inode結構體可以指向同乙個inode_operations結構體。
inode結構體有乙個指向super_block結構體的指標。super_block結構體儲存著從磁碟分割槽的超級塊讀上來的資訊,例如檔案系統型別、塊大小等。super_block結構體的s_root成員是乙個指向dentry的指標,表示這個檔案系統的根目錄被mount到**,在上圖的例子中這個分割槽被mount到/home目錄下。
file、dentry、inode、super_block這幾個結構體組成了vfs的核心概念。對於ext2檔案系統來說,在磁碟儲存布局上也有inode和超級塊的概念,所以很容易和vfs中的概念建立對應關係。而另外一些檔案系統格式來自非unix系統(例如windows的fat32、ntfs),可能沒有inode或超級塊這樣的概念,但為了能mount到linux系統,也只好在驅動程式中硬湊一下,在linux下看fat32和ntfs分割槽會發現許可權位是錯的,所有檔案都是rwxrwxrwx,因為它們本來就沒有inode和許可權位的概念,這是硬湊出來的。
檔案描述符和檔案指標區別
int fileno file stream 返回stream對應的檔案描述符。file fdopen int filedes,const char mode 從檔案描述符fd 到檔案流 file 的函式 檔案描述符,在linux系統中,裝置也是以檔案的形式存在,要對該裝置進行操作就必須先開啟這個檔...
檔案描述符和檔案指標的區別
檔案描述符 在linux系統中開啟檔案就會獲得檔案描述符,它是個很小的正整數。每個程序在pcb process control block 中儲存著乙份檔案描述符表,檔案描述符就是這個表的索引,每個表項都有乙個指向已開啟檔案的指標。檔案指標 c語言中使用檔案指標做為i o的控制代碼。檔案指標指向程序...
檔案描述符和檔案指標的區別
檔案描述符就是open檔案時產生的乙個整數,直到乙個索引作用,它用於unix系統中,用於標識檔案。檔案指標是指向乙個file的結構體,這個結構體裡有乙個元素就是檔案描述符。它用於ansi c標準的io庫呼叫中,用於標識檔案。既然file中包含檔案描述符元素,可以用fopen 直接獲取指標fp,然後使...