標(biāo)準庫中的文件不是通過文件描述符描述的,而是使用文件指針描述的.文件指針是一個指向包含文件各種信息的結(jié)構(gòu)的指針,該結(jié)構(gòu)包含下列內(nèi)容:一個指向緩沖區(qū)的指針,通過它可以一次讀入文件的一大塊內(nèi)容;一個記錄緩沖區(qū)中剩余字符數(shù)的計數(shù)器;一個指向緩沖區(qū)中下一個字符的指針;文件描述符;描述讀/寫模式的標(biāo)志;描述錯誤狀態(tài)的標(biāo)志等.
描述文件的數(shù)據(jù)結(jié)構(gòu)包含在頭文件<stdio.h>中,任何需要使用標(biāo)準輸入/輸出庫中函數(shù)的程序都必須在源文件中包含這個頭文件,此文件也被庫中的其他函數(shù)包含.只供標(biāo)準庫中其他函數(shù)使用的名字以下劃線開始,因此一般不會與用戶程序中的名字沖突,所有的標(biāo)準庫函數(shù)都遵循該約定.
后面那個一大串的定義真是夠復(fù)雜的.
從網(wǎng)上摘下來的一段解釋.
我們知道,當(dāng)我們從鍵盤輸入數(shù)據(jù)的時候,數(shù)據(jù)并不是直接被我們得到,而是放在了緩沖區(qū)中,然后我們從緩沖區(qū)中得到我們想要的數(shù)據(jù) 。如果我們通過setbuf()或setvbuf()函數(shù)將緩沖區(qū)設(shè)置10個字節(jié)的大小,而我們從鍵盤輸入了20個字節(jié)大小的數(shù)據(jù),這樣我們輸入的前10個數(shù)據(jù)會放在緩沖區(qū)中,因為我們設(shè)置的緩沖區(qū)的大小只能夠裝下10個字節(jié)大小的數(shù)據(jù),裝不下20個字節(jié)大小的數(shù)據(jù)。那么剩下的那10個字節(jié)大小的數(shù)據(jù)怎么辦呢?暫時放在了輸入流中。
再說一下 FILE 結(jié)構(gòu)體中幾個相關(guān)成員的含義:
cnt 剩余的字符,如果是輸入緩沖區(qū),那么就表示緩沖區(qū)中還有多少個字符未被讀取
ptr 下一個要被讀取的字符的地址
base 緩沖區(qū)基地址
我們向緩沖區(qū)中放入了10個字節(jié)大小的數(shù)據(jù),F(xiàn)ILE結(jié)構(gòu)體中的 cnt 變?yōu)榱?0 ,說明此時緩沖區(qū)中有10個字節(jié)大小的數(shù)據(jù)可以讀,同時我們假設(shè)緩沖區(qū)的基地址也就是 base 是0x00428e60 ,它是不變的 ,而此時 ptr 的值也為0x00428e60 ,表示從0x00428e60這個位置開始讀取數(shù)據(jù),當(dāng)我們從緩沖區(qū)中讀取5個數(shù)據(jù)的時候,cnt 變?yōu)榱? ,表示緩沖區(qū)還有5個數(shù)據(jù)可以讀,ptr 則變?yōu)榱?x0042e865表示下次應(yīng)該從這個位置開始讀取緩沖區(qū)中的數(shù)據(jù) ,如果接下來我們再讀取5個數(shù)據(jù)的時候,cnt 則變?yōu)榱? ,表示緩沖區(qū)中已經(jīng)沒有任何數(shù)據(jù)了,ptr 變?yōu)榱?x0042869表示下次應(yīng)該從這個位置開始從緩沖區(qū)中讀取數(shù)據(jù),但是此時緩沖區(qū)中已經(jīng)沒有任何數(shù)據(jù)了,所以要將輸入流中的剩下的那10個數(shù)據(jù)放進來,這樣緩沖區(qū)中又有了10個數(shù)據(jù),此時 cnt 變?yōu)榱?0 ,注意了剛才我們講到 ptr 的值是0x00428e69 ,而當(dāng)緩沖區(qū)中重新放進來數(shù)據(jù)的時候這個 ptr 的值變?yōu)榱?x00428e60 ,這是因為當(dāng)緩沖區(qū)中沒有任何數(shù)據(jù)的時候要將 ptr 這個值進行一下刷新,使其指向緩沖區(qū)的基地址也就是0x0042e860這個值!因為下次要從這個位置開始讀取數(shù)據(jù)!
在這里有點需要說明:當(dāng)我們從鍵盤輸入字符串的時候需要敲一下回車鍵才能夠?qū)⑦@個字符串送入到緩沖區(qū)中,那么敲入的這個回車鍵(\r)會被轉(zhuǎn)換為一個換行符\n,這個換行符\n也會被存儲在緩沖區(qū)中并且被當(dāng)成一個字符來計算!比如我們在鍵盤上敲下了123456這個字符串,然后敲一下回車鍵(\r)將這個字符串送入了緩沖區(qū)中,那么此時緩沖區(qū)中的字節(jié)個數(shù)是7 ,而不是6。
緩沖區(qū)的刷新就是將指針 ptr 變?yōu)榫彌_區(qū)的基地址 ,同時 cnt 的值變?yōu)? ,因為緩沖區(qū)刷新后里面是沒有數(shù)據(jù)的
然后看一下下面的代碼.這這是一個簡易版本,了解即可.
首先確定輸入的參數(shù)是否符合要求.
然后在_iob結(jié)構(gòu)數(shù)組中查找空位.
_iob數(shù)組的每個元素都是一個FILE類型的結(jié)構(gòu).
所以遍歷數(shù)組元素中FILE類型的flag成員,判斷是否為空.就是flag與_READ和_WRITE進行與操作后不等于0.(因為flag是空著(這個元素沒有進行讀或?qū)懖僮?的話就是0而0對于任何二進制的與操作都是0)
然后如果fp這個結(jié)構(gòu)指針超過了_iob數(shù)組的范圍,那么就是沒有位置.因為如果有位置之前的循環(huán)就會跳出從而不會超過_iob數(shù)組的范圍.
然后就是依照參數(shù)的類型(r,w,a)去執(zhí)行相應(yīng)的操作.
如果是w就新創(chuàng)建一個文件..
如果是a就先打開這個文件,如果發(fā)生錯誤那就創(chuàng)建這個文件.然后用lseek去將寫入的位置移動到末尾.
否則就只是打開該文件即可.
然后將_iob這個保存已打開文件數(shù)組的該文件位置的內(nèi)容初始化.
然后看一下_fillbuf函數(shù)的內(nèi)容.
因為_fillbuf只針對讀取進行緩沖操作.所以如果不是讀取將會直接退出函數(shù)并返回EOF.
然后判斷是否需要緩沖.,如果不需要則將緩沖大小設(shè)為1,實際上也就沒有了緩沖.來一個走一個.
然后如果參數(shù)這個文件還未分配緩沖區(qū),則繼續(xù)判斷是否有足夠空間或沒有錯誤的分配空間進行緩存.
然后將緩沖區(qū)的開頭給ptr這個指針,由ptr進行遍歷緩沖區(qū)操作.
然后通過read讀取文件fd的bufsize個字符保存到ptr指向的緩沖區(qū)中.然后將讀取的數(shù)量給cnt進行保存.
然后判斷文件是否到末尾或者發(fā)生了錯誤.
正常情況下到末尾cnt都是0,然后先自減的話就是-1,就是正常結(jié)束.如果其他情況就是錯誤的.
然后返回ptr指向的緩沖區(qū)中的字符.
下面那個定義也懶得說了.
然后是練習(xí)8-2.因為這個練習(xí)基本沒什么變化,而且改變之后的運行速度和代碼的長短都有所退步,所以在這隨便寫一下就好了.
總體就是將之前flag的位操作換成了對其中的各個成員進行對比.也沒什么需要說的.暫時這樣.