內(nèi)核(kernel)利用文件描述符(file descriptor)來訪問文件。文件描述符是非負整數(shù)。打開現(xiàn)存文件或新建文件時,內(nèi)核會返回一個文件描述符。讀寫文件也需要使用文件描述符來指定待讀寫的文件。
文件描述符在形式上是一個非負整數(shù)。實際上,它是一個索引值,指向內(nèi)核為每一個進程所維護的該進程打開文件的記錄表。當程序打開一個現(xiàn)有文件或者創(chuàng)建一個新文件時,內(nèi)核向進程返回一個文件描述符。在程序設計中,一些涉及底層的程序編寫往往會圍繞著文件描述符展開。但是文件描述符這一概念往往只適用于UNIX、Linux這樣的操作系統(tǒng)。[1]
習慣上,標準輸入(standard input)的文件描述符是 0,標準輸出(standard output)是 1,標準錯誤(standard error)是 2。盡管這種習慣并非Unix內(nèi)核的特性,但是因為一些 shell 和很多應用程序都使用這種習慣,因此,如果內(nèi)核不遵循這種習慣的話,很多應用程序?qū)⒉荒苁褂谩?/p>
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 來說,每個進程最多可以打開文件的多少取決于系統(tǒng)內(nèi)存的大小,int 的大小,以及系統(tǒng)管理員設定的限制。Linux 2.4.22 強制規(guī)定最多不能超過 1,048,576 。
文件描述符是由無符號整數(shù)表示的句柄,進程使用它來標識打開的文件。文件描述符與包括相關(guān)信息(如文件的打開模式、文件的位置類型、文件的初始類型等)的文件對象相關(guān)聯(lián),這些信息被稱作文件的上下文。
如何創(chuàng)建文件描述符
進程獲取文件描述符最常見的方法是通過本機子例程open或create獲取或者通過從父進程繼承。后一種方法允許子進程同樣能夠訪問由父進程使用的文件。文件描述符對于每個進程一般是唯一的。當用fork子例程創(chuàng)建某個子進程時,該子進程會獲得其父進程所有文件描述符的副本,這些文件描述符在執(zhí)行fork時打開。在由fcntl、dup和dup2子例程復制或拷貝某個進程時,會發(fā)生同樣的復制過程。
對于每個進程,操作系統(tǒng)內(nèi)核在u_block結(jié)構(gòu)中維護文件描述符表,所有的文件描述符都在該表中建立索引。
特點
優(yōu)點
文件描述符的好處主要有兩個:
基于文件描述符的I/O操作兼容POSIX標準。
在UNIX、Linux的系統(tǒng)調(diào)用中,大量的系統(tǒng)調(diào)用都是依賴于文件描述符。
例如,下面的代碼就示范了如何基于文件描述符來讀取當前目錄下的一個指定文件,并把文件內(nèi)容打印至Console中。
此外,在Linux系列的操作系統(tǒng)上,由于Linux的設計思想便是把一切設備都視作文件。因此,文件描述符為在該系列平臺上進行設備相關(guān)的編程實際上提供了一個統(tǒng)一的方法。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include
#include <fcntl.h>
int main(void){ int fd; int numbytes; char path[] = "file"; char buf[256]; /*
* O_CREAT: 如果文件不存在則創(chuàng)建
* 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操作系統(tǒng)上(如Windows NT),無法基于這一概念進行編程。
由于文件描述符在形式上不過是個整數(shù),當代碼量增大時,會使編程者難以分清哪些整數(shù)意味著數(shù)據(jù),哪些意味著文件描述符。因此,完成的代碼可讀性也就會變得很差。
定義數(shù)量
如何在不同平臺上定義文件描述符的數(shù)量
文件描述符極限以及可分配給進程的最大大小由資源限制來定義。這些值應當按照在WebLogicServer文檔中建議的、特定于操作系統(tǒng)的文件描述符值來設置:
對于WLS8.1:調(diào)整硬件、操作系統(tǒng)和網(wǎng)絡性能
對于WLS7.0:調(diào)整硬件、操作系統(tǒng)和網(wǎng)絡性能
對于WLS6.1:調(diào)整硬件、操作系統(tǒng)和網(wǎng)絡性能
Unix和Linux都有文件描述符。不過,二者的主要區(qū)別在于如何設置文件描述符的硬極限值、缺省值和配置過程。
Solaris
/usr/bin/ulimit實用程序定義允許單個進程使用的文件描述符的數(shù)量。它的最大值在rlim_fd_max中定義,在缺省情況下,它設置為65,536。只有root用戶才能修改這些內(nèi)核值。
Linux
管理用戶可以在etc/security/limits.conf配置文件中設置他們的文件描述符極限,如下例所示。
softnofile1024
hardnofile4096
系統(tǒng)級文件描述符極限還可以通過將以下三行添加到/etc/rc.d/rc.local啟動腳本中來設置:
#Increasesystem-widefiledescriptorlimit.
echo4096>/proc/sys/fs/file-max
echo16384>/proc/sys/fs/inode-max
Windows
在Windows操作系統(tǒng)上,文件描述符被稱作文件句柄。在Windows2000服務器上,打開文件的句柄極限設置為16,384。此數(shù)量可以在任務管理器的性能摘要中監(jiān)視。
HP-UX
nfile定義打開文件的最大數(shù)量。此值通常由以下公式來確定:
((NPROC*2)+1000),其中NPROC通常為:((MAXUSERS*5)+64)。如果MAXUSERS等于400,則經(jīng)過計算得到此值為
5128。通??梢詫⒋酥翟O高一些。maxfiles是每個進程的軟文件極限,maxfiles_lim是每個進程的硬文件極限。
AIX
文件描述符極限在/etc/security/limits文件中設置,它的缺省值是2000。此極限可以通過ulimit命令或setrlimit子例程來更改。最大大小由OPEN_MAX常數(shù)來定義。
解決方法
對于ANSI C規(guī)范中定義的標準庫的文件I/O操作。ANSI C規(guī)范給出了一個解決方法,就是使用FILE結(jié)構(gòu)體的指針。事實上,UNIX/Linux平臺上的FILE結(jié)構(gòu)體的實現(xiàn)中往往都是封裝了文件描述符變量在其中。
在UNIX/Linux平臺上,對于控制臺(Console)的標準輸
入,標準輸出,標準錯誤輸出也對應了三個文件描述符。它們分別是0,1,2。在實際編程中,如果要操作這三個文件描述符時,建議使
用頭文件中定義的三個宏來表示: STDIN_FILENO,
STDOUT_FILENO以及STDERR_FILENO。 與文件描述符相關(guān)的操作
文件描述符的生成
open(), open64(), creat(), creat64()
socket()
pipe()
與單一文件描述符相關(guān)的操作
read(), write()
recv(), send()
recvmsg(),sendmsg()
sendfile()
lseek(), lseek64()
fstat(), fstat64()
fchmod()
fchown()
與復數(shù)文件描述符相關(guān)的操作
select(), pselect()
poll()
與文件描述符表相關(guān)的操作
close()
dup()
dup2()
fcntl (F_DUPFD)
fcntl (F_GETFD and F_SETFD)
改變進程狀態(tài)的操作
fchdir()
mmap()
與文件加鎖的操作
flock()
fcntl (F_GETLK, F_SETLK and F_SETLKW)
lockf()
與套接字相關(guān)的操作
connect()
bind()
listen()
accept()
getsockname()
getpeername()
getsockopt(), setsockopt()
shutdown()
文件描述符與文件指針的區(qū)別
文件描述符:在linux系統(tǒng)中打開文件就會獲得文件描述符,它是個很小
的正整數(shù)。每個進程在PCB(Process Control
Block)中保存著一份文件描述符表,文件描述符就是這個表的索引,每個表項都有一個指向已打開文件的指針。文件指針:C語言中使用文件指針做為I/O
的句柄。文件指針指向進程用戶區(qū)中的一個被稱為FILE結(jié)構(gòu)的數(shù)據(jù)結(jié)構(gòu)。FILE結(jié)構(gòu)包括一個緩沖區(qū)和一個文件描述符。而文件描述符是文件描述符表的一個
索引,因此從某種意義上說文件指針就是句柄的句柄(在Windows系統(tǒng)上,文件描述符被稱作文件句柄)。