C語言FILE結構體以及緩衝區深入探討
在C語言中,用一個指標變數指向一個檔案,這個指標稱為檔案指標。通過檔案指標就可對它所指的檔案進行各種操作。
定義檔案指標的一般形式為:
FILE *fp;
這裡的FILE,實際上是在stdio.h中定義的一個結構體,該結構體中含有檔名、檔案狀態和檔案當前位置等資訊,fopen 返回的就是FILE型別的指標。
注意:FILE是檔案緩衝區的結構,fp也是指向檔案緩衝區的指標。
不同編譯器 stdio.h 標頭檔案中對 FILE 的定義略有差異,這裡以標準C舉例說明:
typedef struct _iobuf { int cnt; // 剩餘的字元,如果是輸入緩衝區,那麼就表示緩衝區中還有多少個字元未被讀取 char *ptr; // 下一個要被讀取的字元的地址 char *base; // 緩衝區基地址 int flag; // 讀寫狀態標誌位 int fd; // 檔案描述符 // 其他成員 } FILE;
下面說一下如果控制緩衝區。
我們知道,當我們從鍵盤輸入資料的時候,資料並不是直接被我們得到,而是放在了緩衝區中,然後我們從緩衝區中得到我們想要的資料 。如果我們通過setbuf()或setvbuf()函式將緩衝區設定10個位元組的大小,而我們從鍵盤輸入了20個位元組大小的資料,這樣我們輸入的前10個數據會放在緩衝區中,因為我們設定的緩衝區的大小隻能夠裝下10個位元組大小的資料,裝不下20個位元組大小的資料。那麼剩下的那10個位元組大小的資料怎麼辦呢?暫時放在了輸入流中。請看下圖:
上面的箭頭表示的區域就相當是一個輸入流,紅色的地方相當於一個開關,這個開關可以控制往深綠色區域(標註的是緩衝區)裡放進去的資料,輸入20個位元組的資料只往緩衝區中放進去了10個位元組,剩下的10個位元組的資料就被停留在了輸入流裡!等待下去往緩衝區中放入!接下來系統是如何來控制這個緩衝區呢?
再說一下 FILE 結構體中幾個相關成員的含義:
cnt // 剩餘的字元,如果是輸入緩衝區,那麼就表示緩衝區中還有多少個字元未被讀取ptr // 下一個要被讀取的字元的地址
base // 緩衝區基地址
在上面我們向緩衝區中放入了10個位元組大小的資料,FILE結構體中的 cnt 變為了10 ,說明此時緩衝區中有10個位元組大小的資料可以讀,同時我們假設緩衝區的基地址也就是 base 是0x00428e60 ,它是不變的 ,而此時 ptr 的值也為0x00428e60 ,表示從0x00428e60這個位置開始讀取資料,當我們從緩衝區中讀取5個數據的時候,cnt 變為了5 ,表示緩衝區還有5個數據可以讀,ptr 則變為了0x0042e865表示下次應該從這個位置開始讀取緩衝區中的資料 ,如果接下來我們再讀取5個數據的時候,cnt 則變為了0 ,表示緩衝區中已經沒有任何資料了,ptr 變為了0x0042869表示下次應該從這個位置開始從緩衝區中讀取資料,但是此時緩衝區中已經沒有任何資料了,所以要將輸入流中的剩下的那10個數據放進來,這樣緩衝區中又有了10個數據,此時 cnt 變為了10 ,注意了剛才我們講到 ptr 的值是0x00428e69 ,而當緩衝區中重新放進來資料的時候這個 ptr 的值變為了0x00428e60 ,這是因為當緩衝區中沒有任何資料的時候要將 ptr 這個值進行一下重新整理,使其指向緩衝區的基地址也就是0x0042e860這個值!因為下次要從這個位置開始讀取資料!
在這裡有點需要說明:當我們從鍵盤輸入字串的時候需要敲一下回車鍵才能夠將這個字串送入到緩衝區中,那麼敲入的這個回車鍵(\r)會被轉換為一個換行符\n,這個換行符\n也會被儲存在緩衝區中並且被當成一個字元來計算!比如我們在鍵盤上敲下了123456這個字串,然後敲一下回車鍵(\r)將這個字串送入了緩衝區中,那麼此時緩衝區中的位元組個數是7 ,而不是6。
緩衝區的重新整理就是將指標 ptr 變為緩衝區的基地址 ,同時 cnt 的值變為0 ,因為緩衝區重新整理后里面是沒有資料的!