Linux c学习--从标准输入输出看流和缓冲区
學(xué)習(xí)標(biāo)準(zhǔn)輸入輸出,我們都會(huì)遇到一個(gè)概念,流和緩沖區(qū),但到底什么是流,什么是緩沖區(qū)呢?
????? 書(shū)《C Primer Plus》上說(shuō),C程序處理一個(gè)流而不是直接處理文件。后面的解釋十分抽象:『流(stream)是一個(gè)理想化的數(shù)據(jù)流,實(shí)際輸入或輸出映射到這個(gè)數(shù)據(jù)流』。這個(gè)流具體是一個(gè)怎么樣的東西呢?
流這個(gè)定義非常的形象。我們可以這樣理解:???? 你聲明一個(gè)FILE *fp ,并把fopen(某個(gè)文件)返回的值賦予fp這兩個(gè)動(dòng)作就相當(dāng)于建立了一個(gè)水龍頭,當(dāng)你用getc(fp)之類(lèi)的輸入函數(shù)讀取文件字符時(shí)就相當(dāng)于擰開(kāi)了水龍頭,每讀取一個(gè)字符,這個(gè)文件就像水一樣的流動(dòng)一下,fp所指的地址自然就向后移動(dòng)了一位。 [cpp]?view plaincopy
???????你看這個(gè)循環(huán),可以讀取一個(gè)文件的所有字符。如果不是流的話,ch永遠(yuǎn)是第一個(gè)字符,不會(huì)更新。也可以理解為,fp自動(dòng)++(一個(gè)字符的大小)。 ???? 但流的概念意味著什么呢?
--流是獨(dú)立于設(shè)備之外而操縱外設(shè)一種邏輯手段。?
--大多數(shù)外設(shè)都是互異的,所以(操縱)它們需要專(zhuān)門(mén)的編程技術(shù)。?
--流對(duì)程序員隱藏這些不同點(diǎn),而準(zhǔn)許他們以同樣的方式來(lái)處理大多數(shù)外設(shè)。?
--考慮到一連串的字符需要一次讀一個(gè),流(相當(dāng)于)是具有緩沖作用的接口。?
--個(gè)人計(jì)算機(jī)都是基于流架構(gòu)的。
各大權(quán)威對(duì)流的說(shuō)法有些不一致,我認(rèn)為流既是數(shù)據(jù)的源或目的地的抽象,也是源和目的地之間流動(dòng)信息的表示。但流起碼都暗含以下的幾個(gè)方面:?
1、流是一個(gè)抽象的概念,是對(duì)信息的一種表達(dá);在程序中,流就是對(duì)某個(gè)對(duì)象輸入輸出信息的抽象。就像運(yùn)輸工具是對(duì)一切運(yùn)動(dòng)載體的抽象一樣。?
2、流是一種“動(dòng)”的概念,靜止存儲(chǔ)在介質(zhì)上的信息只有當(dāng)它按一定的序列準(zhǔn)備“運(yùn)動(dòng)”時(shí)才稱(chēng)為流。“從程序移進(jìn)或移出字節(jié)”就是“動(dòng)”的表現(xiàn)。靜止的信息具有流的潛力,但不一定是流,就像沒(méi)有汽油不能行走的汽車(chē)一樣,它具有運(yùn)輸工具的潛力,但它還不是運(yùn)輸工具(因?yàn)樗苡锌赡鼙划?dāng)作房子來(lái)用了,我就在大街上看見(jiàn)有精明的商人用火車(chē)車(chē)廂來(lái)做酒吧)。
3、流有源頭也有目的地;程序中各種移動(dòng)的信息都有其源和目的,記得編程(特別是匯編)時(shí),老是要確定好某個(gè)操作的源操作數(shù)和目的操作數(shù)。借用佛教一言也即是:“萬(wàn)物皆有因果”,這也就像長(zhǎng)江一樣,西自唐古拉,而東去太平洋。在高速公路上飛跑的汽車(chē),它必有其出發(fā)地和目的地。
4、流一定帶有某種信息,沒(méi)有任何內(nèi)容的流帶著自身來(lái)表達(dá)“空”信息。就像運(yùn)輸工具一樣,它不運(yùn)貨的時(shí)候就運(yùn)著自己這一身的零件(包括駕駛員)并把一樣?xùn)|西運(yùn)到目的地,那就是它自己和一個(gè)“跑空車(chē)”的信息。流有最小的信息單元就是二進(jìn)制位,含有最小的信息包就是字節(jié),C標(biāo)準(zhǔn)庫(kù)提供兩種類(lèi)型的流:二進(jìn)制流(binary?stream)和文本流(text?stream)。二進(jìn)制流是有未經(jīng)處理的字節(jié)構(gòu)成的序列;文本流是由文本行組成的序列。而在著名的UNIX系統(tǒng)中,文本流和二進(jìn)制流是相同的(identical)。
5、流有源頭也有目的地,那么它必定與源頭和目的地相關(guān)聯(lián)。但人們操作流的時(shí)候,最關(guān)心的還是其目的地,也就是一個(gè)定向(orientation)的意思,就像司機(jī)運(yùn)貨一樣,它首要關(guān)心的問(wèn)題是目的地,而非起點(diǎn)(操作者都知道)。在C語(yǔ)言中,通過(guò)打開(kāi)流來(lái)關(guān)聯(lián)流及其目的地,使用的函數(shù)是fopen(),該函數(shù)返回一個(gè)指向文件的指針(FILE?*),該指針包含了足夠的可以控制流準(zhǔn)確地到達(dá)目的地的信息。
FILE是一個(gè)結(jié)構(gòu)體(摘自TC2.0中stdio.h文件) ? [cpp]?view plaincopy
???? 將它稱(chēng)為流控制結(jié)構(gòu)體(control?structure?for?streams)真好表現(xiàn)出其功能來(lái)。舉個(gè)例子就好像一卡車(chē)司機(jī)要把貨物運(yùn)到X公司,公司主管就會(huì)給他一張地圖及X公司的基本信息,這些材料所提供的信息如果足夠的話,那么它就能指導(dǎo)著司機(jī)準(zhǔn)確地將貨物送達(dá)了。C中FILE這個(gè)結(jié)構(gòu)體所起的作用就好像是運(yùn)輸公司把一切有用的指導(dǎo)信息封裝起來(lái)的檔案袋一樣。而已有關(guān)聯(lián)的流要終止這種關(guān)聯(lián),就必須關(guān)閉流,使用的函數(shù)是fclose(),就像運(yùn)貨公司若不再給X公司運(yùn)貨了,那么他們就必須要終止合作協(xié)議了。
????這里要注意的是:C語(yǔ)言中stdin、stdout、stderr分別是標(biāo)準(zhǔn)輸入流、標(biāo)準(zhǔn)輸出流及標(biāo)準(zhǔn)出錯(cuò)流的邏輯目的,他們都默認(rèn)對(duì)應(yīng)相應(yīng)的物理終端。在程序運(yùn)行伊始,不需要進(jìn)行open()操作,流自動(dòng)打開(kāi)。
? 那緩沖區(qū)又是什么意思呢? 緩沖區(qū)(Buffer):?
? ? 為了匹配計(jì)算機(jī)快速設(shè)備和慢速設(shè)備間的通信步伐,計(jì)算機(jī)中大量使用硬件緩沖區(qū)(如CPU中的Cache,內(nèi)存相對(duì)于硬盤(pán)和CPU),流是傳輸信息的一種邏輯表示,對(duì)流的各種不同操作也可能存在使用緩沖的需求。但是這里的buffer只是一種邏輯概念,不是物理設(shè)備。緩沖區(qū)存在于流與具體的設(shè)備終端或者存儲(chǔ)介質(zhì)上的文件之間。就好像運(yùn)貨到一個(gè)公司里一樣,合同上的要求是運(yùn)到X公司,但是實(shí)際上是真的把貨物運(yùn)到X公司的總部大樓嗎?不是。應(yīng)該是運(yùn)到X公司的倉(cāng)庫(kù)中。這里的倉(cāng)庫(kù)就有點(diǎn)像我們所說(shuō)的緩沖區(qū)了。也可以這么說(shuō),流運(yùn)動(dòng)到目的,先經(jīng)過(guò)的是緩存區(qū)。 ? 以scanf() printf()為例:????????????????????? ??? 緩沖區(qū)(流)負(fù)責(zé)在輸入/輸出設(shè)備和程序之間建立聯(lián)系。 –輸入設(shè)備->內(nèi)存緩沖區(qū)(stdin)->程序 –程序->內(nèi)存緩沖區(qū)(stdout)->輸出設(shè)備 ??? 是一塊臨時(shí)的存儲(chǔ)區(qū)域,或在內(nèi)存中,或在設(shè)備的控制卡上 ? ? . 緩沖類(lèi)型。
標(biāo)準(zhǔn)庫(kù)提供緩沖是為了減少對(duì)read和write的調(diào)用。提供的緩沖有三種類(lèi)型(整理自APUE):
- 全緩沖。
在這種情況下,實(shí)際的I/O操作只有在緩沖區(qū)被填滿(mǎn)了之后才會(huì)進(jìn)行。對(duì)駐留在磁盤(pán)上的文件的操作一般是有標(biāo)準(zhǔn)I/O庫(kù)提供全緩沖。緩沖區(qū)一般是在第一次對(duì)流進(jìn)行I/O操作時(shí),由標(biāo)準(zhǔn)I/O函數(shù)調(diào)用malloc函數(shù)分配得到的。
術(shù)語(yǔ)flush描述了標(biāo)準(zhǔn)I/O緩沖的寫(xiě)操作。緩沖區(qū)可以由標(biāo)準(zhǔn)I/O函數(shù)自動(dòng)flush(例如緩沖區(qū)滿(mǎn)的時(shí)候);或者我們對(duì)流調(diào)用fflush函數(shù)。
- 行緩沖
在這種情況下,只有在輸入/輸出中遇到換行符的時(shí)候,才會(huì)執(zhí)行實(shí)際的I/O操作。這允許我們一次寫(xiě)一個(gè)字符,但是只有在寫(xiě)完一行之后才做I/O操作。一般的,涉及到終端的流--例如標(biāo)注輸入(stdin)和標(biāo)準(zhǔn)輸出(stdout)--是行緩沖的。
- 無(wú)緩沖
標(biāo)準(zhǔn)I/O庫(kù)不緩存字符。需要注意的是,標(biāo)準(zhǔn)庫(kù)不緩存并不意味著操作系統(tǒng)或者設(shè)備驅(qū)動(dòng)不緩存。
我們上面提到標(biāo)準(zhǔn)輸入輸出是行緩沖,即一行滿(mǎn)了才會(huì)刷新,那什么是刷新呢?刷新就是將數(shù)據(jù)從緩沖區(qū)取出來(lái),真正能刷新,要滿(mǎn)足什么條件呢?
1、滿(mǎn)刷新,即一行滿(mǎn)了(1024個(gè)字節(jié))才會(huì)刷新;
2、遇到'\n'會(huì)刷新;
3、調(diào)用fflush()函數(shù);
4、程序結(jié)束 fclose();
我們可以看到上面的程序,應(yīng)為有while(1),程序一直沒(méi)有結(jié)束,沒(méi)有'\n',沒(méi)有滿(mǎn)行,沒(méi)有fflush(),所以并不會(huì)輸出;
這樣理解的話,我們可以改動(dòng)一下了,就寫(xiě)一個(gè)吧,加'\n':
[cpp]?view plaincopy執(zhí)行結(jié)果如下:
[cpp]?view plaincopy
總結(jié)
以上是生活随笔為你收集整理的Linux c学习--从标准输入输出看流和缓冲区的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: VMware安装win7系统
- 下一篇: Linux-nohup命令详解