複製鏈接
請複製以下鏈接發送給好友

文件描述符

鎖定
內核(kernel)利用文件描述符(file descriptor)來訪問文件。文件描述符是非負整數。打開現存文件或新建文件時,內核會返回一個文件描述符。讀寫文件也需要使用文件描述符來指定待讀寫的文件。
中文名
文件描述符
外文名
file descriptor
作    用
內核利用文件描述符來訪問文件
形    式
非負整數

文件描述符提出前提

每一個文件描述符會與一個打開文件相對應,同時,不同的文件描述符也會指向同一個文件。相同的文件可以被不同的進程打開也可以在同一個進程中被多次打開。系統為每一個進程維護了一個文件描述符表,該表的值都是從0開始的,所以在不同的進程中你會看到相同的文件描述符,這種情況下相同文件描述符有可能指向同一個文件,也有可能指向不同的文件。具體情況要具體分析,要理解具體其概況如何,需要查看由內核維護的3個數據結構。
1.進程級的文件描述符表;
2.系統級的打開文件描述符表;
3.文件系統的i-node表。

文件描述符簡介

文件描述符在形式上是一個非負整數。實際上,它是一個索引值,指向內核為每一個進程所維護的該進程打開文件的記錄表。當程序打開一個現有文件或者創建一個新文件時,內核向進程返回一個文件描述符。在程序設計中,一些涉及底層的程序編寫往往會圍繞着文件描述符展開。但是文件描述符這一概念往往只適用於UNIXLinux這樣的操作系統。
習慣上,標準輸入(standard input)的文件描述符是 0,標準輸出(standard output)是 1,標準錯誤(standard error)是 2。儘管這種習慣並非Unix內核的特性,但是因為一些 shell 和很多應用程序都使用這種習慣,因此,如果內核不遵循這種習慣的話,很多應用程序將不能使用。
POSIX 定義了 STDIN_FILENO、STDOUT_FILENO 和 STDERR_FILENO 來代替 0、1、2。這三個符號常量的定義位於頭文件 unistd.h。
文件描述符的有效範圍是 0 到 OPEN_MAX。一般來説,每個進程最多可以打開 64 個文件(0 — 63)。對於 FreeBSD 5.2.1、Mac OS X 10.3 和 Solaris 9 來説,每個進程最多可以打開文件的多少取決於系統內存的大小,int 的大小,以及系統管理員設定的限制。Linux 2.4.22 強制規定最多不能超過 1,048,576 。
文件描述符是由無符號整數表示的句柄,進程使用它來標識打開的文件。文件描述符與包括相關信息(如文件的打開模式、文件的位置類型、文件的初始類型等)的文件對象相關聯,這些信息被稱作文件的上下文。
如何創建文件描述符
進程獲取文件描述符最常見的方法是通過本機子例程open或create獲取或者通過從父進程繼承。後一種方法允許子進程同樣能夠訪問由父進程使用的文件。文件描述符對於每個進程一般是特定的。當用fork子例程創建某個子進程時,該子進程會獲得其父進程所有文件描述符的副本,這些文件描述符在執行fork時打開。在由fcntl、dup和dup2子例程複製或拷貝某個進程時,會發生同樣的複製過程。
對於每個進程,操作系統內核在u_block結構中維護文件描述符表,所有的文件描述符都在該表中建立索引。 [1] 

文件描述符特點

文件描述符優點

文件描述符的好處主要有兩個:
基於文件描述符的I/O操作兼容POSIX標準。
UNIXLinux系統調用中,大量的系統調用都是依賴於文件描述符。
例如,下面的代碼就示範瞭如何基於文件描述符來讀取當前目錄下的一個指定文件,並把文件內容打印至Console中。
此外,在Linux系列的操作系統上,由於Linux的設計思想便是把一切設備都視作文件。因此,文件描述符為在該系列平台上進行設備相關的編程實際上提供了一個統一的方法。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void){ int fd; int numbytes; char path[] = "file"; char buf[256]; /*
* O_CREAT: 如果文件不存在則創建
* O_RDONLY:以只讀模式打開文件
*/
fd = open(path, O_CREAT | O_RDONLY, 0644);
if(fd < 0){ perror("open()");
exit(EXIT_FAILURE); } memset(buf, 0x00, 256);
while((numbytes = read(fd, buf, 255)) > 0){ printf("%d bytes read: %s", numbytes, buf);
memset(buf, 0x00, 256);
} close(fd);
exit(EXIT_SUCCESS);}

文件描述符缺點

文件描述符的概念存在兩大缺點:
在非UNIX/Linux操作系統上(如Windows NT),無法基於這一概念進行編程。
由於文件描述符在形式上不過是個整數,當代碼量增大時,會使編程者難以分清哪些整數意味着數據,哪些意味着文件描述符。因此,完成的代碼可讀性也就會變得很差。

文件描述符定義數量

如何在不同平台上定義文件描述符的數量
文件描述符極限以及可分配給進程的最大大小由資源限制來定義。這些值應當按照在WebLogicServer文檔中建議的、特定於操作系統的文件描述符值來設置:
對於WLS8.1:調整硬件、操作系統和網絡性能
對於WLS7.0:調整硬件、操作系統和網絡性能
對於WLS6.1:調整硬件、操作系統和網絡性能
Unix和Linux都有文件描述符。不過,二者的主要區別在於如何設置文件描述符的硬極限值、缺省值和配置過程。
Solaris
/usr/bin/ulimit實用程序定義允許單個進程使用的文件描述符的數量。它的最大值在rlim_fd_max中定義,在缺省情況下,它設置為65,536。只有root用户才能修改這些內核值。
Linux
管理用户可以在etc/security/limits.conf配置文件中設置他們的文件描述符極限,如下例所示。
softnofile1024
hardnofile4096
系統級文件描述符極限還可以通過將以下三行添加到/etc/rc.d/rc.local啓動腳本中來設置:
#Increasesystem-widefiledescriptorlimit.
echo4096>/proc/sys/fs/file-max
echo16384>/proc/sys/fs/inode-max
Windows
在Windows操作系統上,文件描述符被稱作文件句柄。在Windows2000服務器上,打開文件的句柄極限設置為16,384。此數量可以在任務管理器的性能摘要中監視。
HP-UX
nfile定義打開文件的最大數量。此值通常由以下公式來確定:((NPROC*2)+1000),其中NPROC通常為:((MAXUSERS*5)+64)。如果MAXUSERS等於400,則經過計算得到此值為5128。通常可以將此值設高一些。maxfiles是每個進程的軟文件極限,maxfiles_lim是每個進程的硬文件極限。
AIX
文件描述符極限在/etc/security/limits文件中設置,它的缺省值是2000。此極限可以通過ulimit命令或setrlimit子例程來更改。最大大小由OPEN_MAX常數來定義。 [2] 

文件描述符解決方法

對於ANSI C規範中定義的標準庫的文件I/O操作。ANSI C規範給出了一個解決方法,就是使用FILE結構體指針。事實上,UNIX/Linux平台上的FILE結構體的實現中往往都是封裝了文件描述符變量在其中。
在UNIX/Linux平台上,對於控制枱(Console)的標準輸入,標準輸出,標準錯誤輸出也對應了三個文件描述符。它們分別是0,1,2。在實際編程中,如果要操作這三個文件描述符時,建議使用<unistd.h>頭文件中定義的三個宏來表示: STDIN_FILENO, STDOUT_FILENO以及STDERR_FILENO。 與文件描述符相關的操作
文件描述符的生成
open(), open64(), creat(), creat64()
socket()
pipe()
與單一文件描述符相關的操作
read(), write()
recv(), send()
recvmsg(),sendmsg()
sendfile()
lseek(), lseek64()
fstat(), fstat64()
與複數文件描述符相關的操作
select(), pselect()
poll()
與文件描述符表相關的操作
close()
dup()
fcntl (F_DUPFD)
fcntl (F_GETFD and F_SETFD)
改變進程狀態的操作
mmap()
與文件加鎖的操作
flock()
fcntl (F_GETLK, F_SETLK and F_SETLKW)
與套接字相關的操作
connect()
bind()
listen()
accept()
getsockname()
getpeername()
getsockopt(), setsockopt()
shutdown()

文件描述符文件描述符與文件指針的區別

文件描述符:在linux系統中打開文件就會獲得文件描述符,它是個很小的非負整數。每個進程在PCB(Process Control Block)中保存着一份文件描述符表,文件描述符就是這個表的索引,每個表項都有一個指向已打開文件的指針。
文件指針:C語言中使用文件指針做為I/O的句柄。文件指針指向進程用户區中的一個被稱為FILE結構的數據結構。FILE結構包括一個緩衝區和一個文件描述符。而文件描述符是文件描述符表的一個索引,因此從某種意義上説文件指針就是句柄的句柄(在Windows系統上,文件描述符被稱作文件句柄)。 [3] 
參考資料
  • 1.    繆瑨. 基於類型檢查的文件描述符泄露研究[D]. 安徽工業大學, 2016.
  • 2.    朱廣蔚. 文件描述符的面向對象設計[D]. 南京大學, 2004.
  • 3.    吳詠煒. Linux 上實現雙向進程間通信管道[J]. 2004.