內(nèi)核(kernel)利用文件描述符(file descriptor)來(lái)訪問(wèn)文件债蜜。文件描述符是非負(fù)整數(shù)崔涂。打開現(xiàn)存文件或新建文件時(shí)漩怎,內(nèi)核會(huì)返回一個(gè)文件描述符趣竣。讀寫文件也需要使用文件描述符來(lái)指定待讀寫的文件。
文件描述符在形式上是一個(gè)非負(fù)整數(shù)胆剧。實(shí)際上絮姆,它是一個(gè)索引值,指向內(nèi)核為每一個(gè)進(jìn)程所維護(hù)的該進(jìn)程打開文件的記錄表秩霍。當(dāng)程序打開一個(gè)現(xiàn)有文件或者創(chuàng)建一個(gè)新文件時(shí)篙悯,內(nèi)核向進(jìn)程返回一個(gè)文件描述符。在程序設(shè)計(jì)中铃绒,一些涉及底層的程序編寫往往會(huì)圍繞著文件描述符展開鸽照。但是文件描述符這一概念往往只適用于UNIX、Linux這樣的操作系統(tǒng)颠悬。[1]
習(xí)慣上矮燎,標(biāo)準(zhǔn)輸入(standard input)的文件描述符是 0,標(biāo)準(zhǔn)輸出(standard output)是 1赔癌,標(biāo)準(zhǔn)錯(cuò)誤(standard error)是 2诞外。盡管這種習(xí)慣并非Unix內(nèi)核的特性,但是因?yàn)橐恍?shell 和很多應(yīng)用程序都使用這種習(xí)慣灾票,因此峡谊,如果內(nèi)核不遵循這種習(xí)慣的話,很多應(yīng)用程序?qū)⒉荒苁褂谩?/p>
POSIX 定義了 STDIN_FILENO刊苍、STDOUT_FILENO 和 STDERR_FILENO 來(lái)代替 0既们、1、2班缰。這三個(gè)符號(hào)常量的定義位于頭文件 unistd.h贤壁。
文件描述符的有效范圍是 0 到 OPEN_MAX。一般來(lái)說(shuō)埠忘,每個(gè)進(jìn)程最多可以打開 64 個(gè)文件(0 — 63)脾拆。對(duì)于 FreeBSD 5.2.1馒索、Mac OS X 10.3 和 Solaris 9 來(lái)說(shuō),每個(gè)進(jìn)程最多可以打開文件的多少取決于系統(tǒng)內(nèi)存的大小名船,int 的大小绰上,以及系統(tǒng)管理員設(shè)定的限制。Linux 2.4.22 強(qiáng)制規(guī)定最多不能超過(guò) 1,048,576 渠驼。
文件描述符是由無(wú)符號(hào)整數(shù)表示的句柄蜈块,進(jìn)程使用它來(lái)標(biāo)識(shí)打開的文件。文件描述符與包括相關(guān)信息(如文件的打開模式迷扇、文件的位置類型百揭、文件的初始類型等)的文件對(duì)象相關(guān)聯(lián),這些信息被稱作文件的上下文蜓席。
如何創(chuàng)建文件描述符
進(jìn)程獲取文件描述符最常見的方法是通過(guò)本機(jī)子例程open或create獲取或者通過(guò)從父進(jìn)程繼承器一。后一種方法允許子進(jìn)程同樣能夠訪問(wèn)由父進(jìn)程使用的文件。文件描述符對(duì)于每個(gè)進(jìn)程一般是唯一的厨内。當(dāng)用fork子例程創(chuàng)建某個(gè)子進(jìn)程時(shí)祈秕,該子進(jìn)程會(huì)獲得其父進(jìn)程所有文件描述符的副本,這些文件描述符在執(zhí)行fork時(shí)打開雏胃。在由fcntl请毛、dup和dup2子例程復(fù)制或拷貝某個(gè)進(jìn)程時(shí),會(huì)發(fā)生同樣的復(fù)制過(guò)程瞭亮。
對(duì)于每個(gè)進(jìn)程方仿,操作系統(tǒng)內(nèi)核在u_block結(jié)構(gòu)中維護(hù)文件描述符表,所有的文件描述符都在該表中建立索引街州。
特點(diǎn)
優(yōu)點(diǎn)
文件描述符的好處主要有兩個(gè):
基于文件描述符的I/O操作兼容POSIX標(biāo)準(zhǔn)兼丰。
在UNIX、Linux的系統(tǒng)調(diào)用中唆缴,大量的系統(tǒng)調(diào)用都是依賴于文件描述符。
例如,下面的代碼就示范了如何基于文件描述符來(lái)讀取當(dāng)前目錄下的一個(gè)指定文件黍翎,并把文件內(nèi)容打印至Console中面徽。
此外,在Linux系列的操作系統(tǒng)上匣掸,由于Linux的設(shè)計(jì)思想便是把一切設(shè)備都視作文件趟紊。因此,文件描述符為在該系列平臺(tái)上進(jìn)行設(shè)備相關(guān)的編程實(shí)際上提供了一個(gè)統(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);}
缺點(diǎn)
文件描述符的概念存在兩大缺點(diǎn):
在非UNIX/Linux操作系統(tǒng)上(如Windows NT)霎匈,無(wú)法基于這一概念進(jìn)行編程。
由于文件描述符在形式上不過(guò)是個(gè)整數(shù)送爸,當(dāng)代碼量增大時(shí)铛嘱,會(huì)使編程者難以分清哪些整數(shù)意味著數(shù)據(jù)暖释,哪些意味著文件描述符。因此墨吓,完成的代碼可讀性也就會(huì)變得很差球匕。
定義數(shù)量
如何在不同平臺(tái)上定義文件描述符的數(shù)量
文件描述符極限以及可分配給進(jìn)程的最大大小由資源限制來(lái)定義。這些值應(yīng)當(dāng)按照在WebLogicServer文檔中建議的帖烘、特定于操作系統(tǒng)的文件描述符值來(lái)設(shè)置:
對(duì)于WLS8.1:調(diào)整硬件亮曹、操作系統(tǒng)和網(wǎng)絡(luò)性能
對(duì)于WLS7.0:調(diào)整硬件、操作系統(tǒng)和網(wǎng)絡(luò)性能
對(duì)于WLS6.1:調(diào)整硬件秘症、操作系統(tǒng)和網(wǎng)絡(luò)性能
Unix和Linux都有文件描述符照卦。不過(guò),二者的主要區(qū)別在于如何設(shè)置文件描述符的硬極限值乡摹、缺省值和配置過(guò)程役耕。
Solaris
/usr/bin/ulimit實(shí)用程序定義允許單個(gè)進(jìn)程使用的文件描述符的數(shù)量。它的最大值在rlim_fd_max中定義趟卸,在缺省情況下蹄葱,它設(shè)置為65,536。只有root用戶才能修改這些內(nèi)核值锄列。
Linux
管理用戶可以在etc/security/limits.conf配置文件中設(shè)置他們的文件描述符極限图云,如下例所示。
softnofile1024
hardnofile4096
系統(tǒng)級(jí)文件描述符極限還可以通過(guò)將以下三行添加到/etc/rc.d/rc.local啟動(dòng)腳本中來(lái)設(shè)置:
#Increasesystem-widefiledescriptorlimit.
echo4096>/proc/sys/fs/file-max
echo16384>/proc/sys/fs/inode-max
Windows
在Windows操作系統(tǒng)上邻邮,文件描述符被稱作文件句柄竣况。在Windows2000服務(wù)器上,打開文件的句柄極限設(shè)置為16,384筒严。此數(shù)量可以在任務(wù)管理器的性能摘要中監(jiān)視丹泉。
HP-UX
nfile定義打開文件的最大數(shù)量。此值通常由以下公式來(lái)確定:
((NPROC*2)+1000)鸭蛙,其中NPROC通常為:((MAXUSERS*5)+64)摹恨。如果MAXUSERS等于400,則經(jīng)過(guò)計(jì)算得到此值為
5128娶视。通成购澹可以將此值設(shè)高一些。maxfiles是每個(gè)進(jìn)程的軟文件極限肪获,maxfiles_lim是每個(gè)進(jìn)程的硬文件極限寝凌。
AIX
文件描述符極限在/etc/security/limits文件中設(shè)置,它的缺省值是2000孝赫。此極限可以通過(guò)ulimit命令或setrlimit子例程來(lái)更改较木。最大大小由OPEN_MAX常數(shù)來(lái)定義。
解決方法
對(duì)于ANSI C規(guī)范中定義的標(biāo)準(zhǔn)庫(kù)的文件I/O操作青柄。ANSI C規(guī)范給出了一個(gè)解決方法伐债,就是使用FILE結(jié)構(gòu)體的指針预侯。事實(shí)上,UNIX/Linux平臺(tái)上的FILE結(jié)構(gòu)體的實(shí)現(xiàn)中往往都是封裝了文件描述符變量在其中泳赋。
在UNIX/Linux平臺(tái)上雌桑,對(duì)于控制臺(tái)(Console)的標(biāo)準(zhǔn)輸
入,標(biāo)準(zhǔn)輸出祖今,標(biāo)準(zhǔn)錯(cuò)誤輸出也對(duì)應(yīng)了三個(gè)文件描述符校坑。它們分別是0,1,2。在實(shí)際編程中千诬,如果要操作這三個(gè)文件描述符時(shí)耍目,建議使
用頭文件中定義的三個(gè)宏來(lái)表示: 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()
與復(fù)數(shù)文件描述符相關(guān)的操作
select(), pselect()
poll()
與文件描述符表相關(guān)的操作
close()
dup()
dup2()
fcntl (F_DUPFD)
fcntl (F_GETFD and F_SETFD)
改變進(jìn)程狀態(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)中打開文件就會(huì)獲得文件描述符徐绑,它是個(gè)很小
的正整數(shù)邪驮。每個(gè)進(jìn)程在PCB(Process Control
Block)中保存著一份文件描述符表,文件描述符就是這個(gè)表的索引傲茄,每個(gè)表項(xiàng)都有一個(gè)指向已打開文件的指針毅访。文件指針:C語(yǔ)言中使用文件指針做為I/O
的句柄。文件指針指向進(jìn)程用戶區(qū)中的一個(gè)被稱為FILE結(jié)構(gòu)的數(shù)據(jù)結(jié)構(gòu)盘榨。FILE結(jié)構(gòu)包括一個(gè)緩沖區(qū)和一個(gè)文件描述符喻粹。而文件描述符是文件描述符表的一個(gè)
索引,因此從某種意義上說(shuō)文件指針就是句柄的句柄(在Windows系統(tǒng)上草巡,文件描述符被稱作文件句柄)守呜。