文件標識符(fd)和FILE結構體

前言:
fopen,fclose,fwrite,fread屬於C庫當中的函數,爲庫函數調用。而open,close,write,read這幾個函數屬於系統提供的藉口,稱之爲系統調用。庫函數和系統調用是上下級關係,在庫函數中封裝了系統調用的函數。(庫函數爲啥都有的大哥,系統調用就是有一部分的小弟)

一、文件描述符fd

1、簡介

文件描述符就是以0開始的一個小整數(文件描述符無負數)

而且Linux進程默認情況下會有三個缺省打開的文件描述符:標準輸入(stdin)、標準輸出(stdout)、標準錯誤(stderror)。它們三個所對應的整數爲0、1、2,對應的物理設備爲鍵盤、顯示器、顯示器

當我們打開一個文件的時候,操作系統在內存中會創建相應的數據結構來描述這個文件,所以就有了file結構體。當進程執行open系統調用的時候,就需要將文件和進程關聯起來,每個進程都有一個指針files*,指向表files_struct,表中最重要的就是包含指針數組,本質上,文件描述符就是該指針數組的下標。只要能夠拿到文件描述符(即下標),就可打開對應的文件。
這裏寫圖片描述

2、文件描述符(fd)的分配規則
在Linux下打開一個文件時,POSIX標準要求每次打開時必須使用當前進程中最小的文件描述符(非負整數)。操作系統會默認將0、1、2分別給標準輸入、標準輸出和標準錯誤,此時要打開一個文件時,系統就會將files_struct數組中下標最小的3開始分配。
倘若關閉0,此時打開兩個個文件,則第一個被打開文件的文件描述符爲0,第二個文件的文件描述符爲3。關閉2也是如此,但不要輕易關閉1,這樣就無法在屏幕上輸出了。(大家可以自行驗證一下)

二、FILE 結構體

  FILE 結構體裏面有 兩個非常重要的字段:文件描述符(fd)和緩衝區

1、文件描述符
可見上面具體內容

2、緩衝區

先來看一段代碼:

test.c
#include <stdio.h>
#include <string.h>
 int main()
 {
      const char *msg1 = "beautiful gril printf\n";
       const char *msg2 = "beautiful gril fwrite\n";
       const char *msg3 = "beautiful gril write\n";

     printf("%s",msg1);
     fwrite(msg2,strlen(msg1),1,stdout);
     write(1,msg3,strlen(msg3));

     fork();
     return 0;
 }

這裏寫圖片描述
這裏寫圖片描述
通過上述結果發現file文件裏的printf和fwrite函數都輸出了兩遍,而write函數只輸出了一遍。這是爲什麼嘞?
解釋:
因爲一般C庫函數有三種類型的緩衝區:一是無緩衝;二是寫入文件的時候都是全緩衝;三是寫入顯示器是行緩衝。printf函數和fwrite函數都是C庫函數,自帶緩衝區,當發生重定向到普通文件的時候,數據的緩衝方式會由行緩衝變爲全緩衝,而我們放進文件的數據不會被立即刷新(甚至是在fork之後),在進程退出之後,會統一刷新寫入到文件中。但是在fork之後,父子數據會發生寫時拷貝,即當父進程刷新時,子進程也就有了同樣的數據,所以就會產生兩份數據。而write函數爲系統調用,無緩衝區。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章