Linux下 檔案描述符(fd)與 檔案指標(FILE*)
一、檔案描述符(fd)
我們都知道在Linux下一切皆檔案。當然裝置也不例外,如果要對某個裝置進行操作,就不得不開啟此裝置檔案,開啟檔案就會獲得該檔案的檔案描述符fd( file discriptor), 它就是一個很小的整數,每個程序在PCB(Process Control Block)中儲存著一份檔案描述符表,檔案描述符就是這個表的索引,每個表項都有一個指向已開啟檔案的指標。
圖中檔案描述符即為檔案描述符陣列的下標
檔案描述符的分配規律:從當前未使用的最小的整數開始分配;
檔案描述符的缺點:
不能移植到UNIX以外的系統上去,也不直觀。
舉一個系統函式的例子:ssize_t write ( int fd, const void *buf, size_t count);
write: 是系統寫函式 fd: 檔案描述符 (一個整數) *buf: 內容寫在哪裡 count: 一次寫多少個;
概括:
每一個程序在PCB(Process Control Block)即程序控制塊中都儲存著一分檔案描述符表,檔案描述符就是這個表的索引,檔案描述符表中每個表項都有一個指向已開啟檔案的指標。現在我們明確一下:已開啟的檔案在核心中用file結構體表示,檔案描述符表中的指標指向file結構體。
fd詳解
fd:為開啟檔案的檔案描述符,而每個程序都有一張檔案描述符表,fd檔案描述符就是這張表的索引,同樣這張表中有一表項,該表項又是指向前面提到開啟檔案的file結構體,file結構體才是核心中用來描述檔案屬性的結構體。
FILE結構體
1、FILE結構體中的成員
緩衝區基址,緩衝區當前指標,緩衝區大小,緩衝區剩餘位元組數,檔案讀寫方式等。
struct FILE
{
char *_ptr;//檔案輸入的下一個位置
int _cnt;//當前緩衝區的相對位置
char *_base;//指基礎位置(檔案的起始位置)
int _flag;//檔案標誌
int _file;//檔案的有效性驗證
int _charbuf;//檢查緩衝區狀況,如果緩衝區則不讀取
int _bufsiz;//檔案的大小
char *_tmpfname;//臨時檔名
};
2、(FILE*)檔案指標
檔案指標指向程序使用者區中一個被叫做FILE結構的結構資料。FILE結構包括一個緩衝區和一個檔案描述符 。而檔案描述符是檔案描述符表的一個索引,因此從某種意義上說檔案指標就是控制代碼的控制代碼(在Windows系統上,檔案描述符被稱作檔案控制代碼)。
通常,任何程式執行起來之後都會預設的開啟三個標準輸入流(stdin:鍵盤),標準輸出流(stdout:顯示器),標準錯誤流(stderr:顯示器)。
檔案描述符與檔案指標的區別
簡單歸納:fd只是一個整數,在open時產生,起到一個索引的作用,程序通過PCB中的檔案描述符表找到該fd所指向的檔案指標file。
open:檔案描述符的操作(如:open)返回的是一個檔案描述符(int fd),核心會在每個程序空間中維護一個檔案描述符表,所有開啟的檔案都將通過,此表中的檔案描述符來引用。
fopen:流(如:fopen)返回的是一個檔案指標(即指向FILE結構體的指標),FILE結構是包含有檔案描述符的,fopen可以看做是open(fd直接操作的系統呼叫)的封裝,它的優點是帶有I/O快取。
C語言的檔案指標與檔案描述符的相互轉換可通過fdopen和fileno兩個函式實現。它們都包含在標頭檔案stdio.h中。
fdopen的原型:
FILE *fdopen(int filedes,const char *opentype);
第一個引數filedes是一個開啟的檔案描述符,opentype是表示開啟方式的字串,和fopen函式具有相同的取值,比如”w”或”w+”等。但是你必須保證該字串的描述和檔案實際的開啟方式是匹配的。函式fopen()就是返回開啟檔案的指標;如果操作失敗,返回空指標null。
把檔案流指標轉換成檔案描述符用fileno函式,
其原型為:
int fileno(FILE *stream);
它返回的是和stream檔案流對應的檔案描述符。如果失敗,返回-1;
當程式執行時,就已經有三個標準檔案流打開了,它們分別是(標準輸入)stdin,(標準輸出)stdout,(標準錯誤輸出)stderr,和流式檔案相對應的是,也有三個檔案描述符被預先佔用(它們分別是:
0((標準輸入)stdin),1((標準輸出)stdout),2((標準錯誤輸)stderr));