第14章輸入輸出和文件_第1頁
第14章輸入輸出和文件_第2頁
第14章輸入輸出和文件_第3頁
第14章輸入輸出和文件_第4頁
第14章輸入輸出和文件_第5頁
已閱讀5頁,還剩52頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、第14章 輸入輸出和文件 輸入和輸出是人和計算機交互的手段,也是計算機生命所在,試想,如果一臺機器既不接受任何形式的指令,也不給出任何形式的結(jié)果,這臺機器的存在就沒有了意義。幾乎每個程序都要用到輸入和輸出,本書給出的示例代碼中,顯示結(jié)果是依靠cout,輸入信息是依靠cin,這兩個都是C+標(biāo)準(zhǔn)庫中ostream類和istream類中提供了對象,此外,C+標(biāo)準(zhǔn)庫還提供了其他類和對象,不僅僅可實現(xiàn)向屏幕輸出、從鍵盤讀入,還可以寫入文件、從文件讀入,本章重點討論輸入輸出和文件相關(guān)內(nèi)容。14.1 輸入輸出概述 C+語言不具備內(nèi)部輸入輸出能力,需要借助外部I/O包來完成,將輸入輸出具體要完成的操作留給編譯

2、器來做,這樣做的目的是為了最大限度地保證語言與平臺的無關(guān)性。因為輸入輸出功能都是與操作系統(tǒng)相關(guān)的,如果C+為某種操作系統(tǒng)實現(xiàn)內(nèi)部輸入輸出功能,那它也就被限制在這個操作系統(tǒng)上了,舉例來說,如果C+為windows內(nèi)部實現(xiàn)了輸入輸出命令,那么該命令就只能用在windows環(huán)境下,在其他系統(tǒng),如linux下將完全不起作用,這大大限制了程序的可移植性。 首先,先讓我們一起來了解幾個概念。14.1.1 什么是文件使用電腦時,經(jīng)常遇到“文件”這個詞,一般意義的理解是“存放在存儲介質(zhì)上的一組信息”,但從程序設(shè)計的角度看,文件的概念要寬泛得多。文件的準(zhǔn)確定義為“存放在外部介質(zhì)上的以文件名為標(biāo)識的數(shù)據(jù)的集合”,

3、此處的外部介質(zhì)不僅僅包括磁盤,還包括設(shè)備,比如鍵盤、顯示器以及打印機等。凡是起到輸入輸出作用,與CPU直接或間接打交道的一組信息集合都是文件。每個文件都以文件名為標(biāo)識,I/O設(shè)備的文件名是系統(tǒng)定義的,如:COM1或AUX第一串行口,附加設(shè)備COM2第二串行口,此外,還可能有COM3、COM4等CON控制臺(console),鍵盤(輸入用)或顯示器(輸出用)LPT1或PRN第一并行口或打印機LPT2第二并行口,還可能有LPT3等NUL空設(shè)備14.1.2 流關(guān)于“流”,可以學(xué)院派地解釋為“流是(表達(dá))讀寫數(shù)據(jù)的一種可移植的方法,它為一般的I/O操作提供了靈活有效的手段。一個流是一個由指針操作的文件

4、或者是一個物理設(shè)備,而這個指針正是指向了這個流?!本虲+程序而言, I/O操作可以簡單地看作是從程序移進(jìn)或移出字節(jié),這種搬運的過程便稱為流(stream)。程序只需要關(guān)心是否正確地輸出了字節(jié)數(shù)據(jù),以及是否正確地輸入了要讀取字節(jié)數(shù)據(jù),特定I/O設(shè)備的細(xì)節(jié)對程序員是隱藏的。C+中,所有的信息都是以0、1編碼,所以,輸出的字節(jié)(也就是0、1序列)代表什么,輸入的源頭或輸出的目的都不是流所關(guān)心的內(nèi)容,流的實質(zhì)在于是否正確完成了運輸任務(wù),形象的表述如所示,左側(cè)是輸入流而右側(cè)是輸出流。14.1.3 緩沖區(qū) 大家可能已對硬件緩沖區(qū)比較熟悉,為了匹配計算機快速設(shè)備和慢速設(shè)備間的通信步伐,計算機中大量使用了硬件

5、緩沖區(qū),如CPU中的Cache,內(nèi)存也可以看成是一種緩沖區(qū),用以高速CPU處理和相對瓶頸的硬盤存儲速度之間的矛盾。 流是傳輸信息的一種邏輯表示,是具有緩沖作用的接口,同樣有緩沖區(qū)的需求,但這里的緩沖區(qū)是一種邏輯概念,和物理設(shè)備中的緩沖區(qū)有所不同。通常,流的緩沖區(qū)是用作中介的內(nèi)存塊,是從設(shè)備傳遞到程序或者由程度傳遞給設(shè)備的臨時存儲池(pool),下面從文件輸入和文件輸出的角度來具體看一下緩沖區(qū)的作用。14.1.4 重定向 標(biāo)準(zhǔn)的輸出和輸入設(shè)備通常指的是顯示器和鍵盤,但一些操作系統(tǒng)支持重定向,這使得標(biāo)準(zhǔn)輸入和輸出能被替換,比如說,一個程序的信息原本是要輸出到屏幕上的,可通過操作系統(tǒng)的支持,在不改變

6、程序的前提下,便可用讓信息輸出到其他位置,以DOS系統(tǒng)來舉例:#include using namespace std;int main()coutHello,txt will be shown on screen;return 0;14.1.5 3種輸入輸出機制C+語言的輸入輸出機制包含3層,前兩層是從傳統(tǒng)的C語言繼承而來,分別是底層I/O和高層I/O,第3層是C+中增添的流類庫,這是本章討論的重點。(1)底層I/O:底層I/O依賴于操作系統(tǒng)來實現(xiàn),調(diào)用操作系統(tǒng)的功能對文件進(jìn)行輸入輸出處理,具有較高的速度。底層I/O將外部設(shè)備和磁盤文件都等同于邏輯文件,采用相同的方法進(jìn)行處理,一般過程為“打

7、開文件”、“讀寫文件”,“關(guān)閉文件”,這些是通過一組底層I/O函數(shù)來完成的,這些函數(shù)定義在頭文件io.h中。(2)高層I/O:高層I/O是在底層I/O的基礎(chǔ)上擴展起來的,仍舊將外部設(shè)備和磁盤文件統(tǒng)一處理,但處理的方式更為靈活,提供的一組處理函數(shù)定義在頭文件stdio.h中,新的C+標(biāo)準(zhǔn)頭文件為,提供的這些函數(shù)大體可分為兩類:一般文件函數(shù)(外部設(shè)備和磁盤文件)和標(biāo)準(zhǔn)I/O函數(shù)。(3)流類庫:除了從C語言中繼承了上述兩種I/O機制外,C+還特有一種輸出機制:流類庫(即iostream類庫),這是C+所特有的,iostream類庫為內(nèi)置類型類型對象提供了輸入輸出支持,也支持文件的輸入輸出,另外,類的

8、設(shè)計者可以通過運算符重載機制對iostream庫的擴展,來支持自定義類型的輸入輸出操作。14.2 高層I/O C+中的高層I/O是從C繼承而來,使用頭文件,本節(jié)先從其標(biāo)準(zhǔn)輸入輸出看起,再來學(xué)習(xí)高層I/O中文件的操作,原理上說,流類庫已經(jīng)能勝任幾乎所有的輸入輸出處理,但高層I/O的介紹很有必要,這有助于讀者閱讀原有的代碼。14.2.1 標(biāo)準(zhǔn)輸出函數(shù)printf注意:這里使用的概念是函數(shù),而不是對象,注意printf和cout的不同,這也許就是C和C+思維方式的不同。printf函數(shù)用于將字節(jié)流復(fù)制到標(biāo)準(zhǔn)輸出設(shè)備(通常是屏幕),其使用方式十分靈活,有兩個突出優(yōu)點,一是其參數(shù)表的長度是可變的,二是其

9、轉(zhuǎn)換說明和格式控制十分簡單,printf的參數(shù)表分為兩部分:控制字符串和參數(shù)表,基本格式為:int printf(const char*,para1,para2);進(jìn)一步解釋前,先來看示例代碼14-1:#include /使用printf要包含的頭文件int main()printf(%s is %d years old n, Deco, 24);return 0;14.2.2 標(biāo)準(zhǔn)輸入函數(shù)scanfscanf用于從標(biāo)準(zhǔn)輸入設(shè)備(通常是鍵盤)讀取流數(shù)據(jù)到內(nèi)存中,和printf的使用方法幾乎一致,基本格式為:int scanf(const char*,¶1,¶2);如果控制符和輸

10、入流完全匹配,則返回成功轉(zhuǎn)換的匹配數(shù);如果部分匹配(從前往后),則返回已經(jīng)成功轉(zhuǎn)換的匹配數(shù);如果完全不匹配,則返回0;代碼14-2,進(jìn)行匹配輸入示例。代碼14-3示例了不完全匹配輸入的情況。針對下述代碼如果輸入“3A”這樣的字符則完全匹配,結(jié)果正常,但如果輸入“A3”,則匹配失敗。但輸入的A仍然滯留在緩沖區(qū)中,結(jié)果是num沒有賦值成功,A則賦值給了chrscanf(“%d”, &num);Scanf(“%c”, &chr);解決方法:使用清除標(biāo)準(zhǔn)輸入緩沖區(qū)函數(shù)fflush(stdin) 。除了%c之外,%d, %s等都會自動跳過前導(dǎo)空格和換行符等。在%c前加一個空格,則可達(dá)到同樣效果。%與轉(zhuǎn)換

11、字符間加星號(*)表示讀取指定類型的數(shù)據(jù),但不存儲。如scanf(“%d %*d %d”, &x, &y);輸入10/20后x=10, y=20,“/”雖然被讀取但不保存。14.2.3 掃描集 對scanf函數(shù)而言,掃描集(scanset)是個十分重要的概念。掃描集定義一個字符集合,可由scanf()讀入其中允許的字符并賦給對應(yīng)字符數(shù)組。掃描集合由一對方括號中的一串字符定義,左方括號前必須綴以百分號。 特定掃描集:如%ABC使scanf()讀入字符A、B和C組成字符串 范圍掃描集:如%0-9使scanf()讀入當(dāng)前輸入流中的數(shù)字,碰到非數(shù)字結(jié)束。 反向掃描集:如%Q在碰到非Q時字符時會一直接收

12、輸入,直到碰到Q才結(jié)束scanf()14.2.4 sprintf和sscanf 函數(shù)sprintf和sscanf分別是printf和scanf的串版本(在原函數(shù)的基礎(chǔ)上增加了s前綴而得名),他們的原型分別為:int sprintf(char* s,控制字符串,參數(shù)表);int sscanf(const char* s ,控制字符串,參數(shù)表); 參數(shù)表中參數(shù)的個數(shù)同樣是任意的,與printf和scanf函數(shù)相比,串版本不再和標(biāo)準(zhǔn)輸入輸出流相關(guān)聯(lián)。 sscanf是從C風(fēng)格字符串變量中讀取值存儲到變量中, sprintf是向C風(fēng)格字符串變量寫入字符,見示例代碼14-414.2.5 fprintf和f

13、scanf函數(shù) f前綴代表file,這里,輸入輸出設(shè)備不再是鍵盤和顯示器,也不是sscanf和sprintf中的C風(fēng)格字符串,而是文件。 fprintf和fscanf的原型為:int fprintf(FILE* ofp,控制字符串,參數(shù)表);/向文件寫入格式化的字符串int fscanf(FILE* ifp ,控制字符串,參數(shù)表);/根據(jù)控制串從文件讀內(nèi)容賦值給相應(yīng)的變量。 頭文件包含了文件結(jié)構(gòu)FILE、stdin、stdout和stderr的定義,因此使用這2個函數(shù)時一般要#include 見備注代碼14.2.6 文件訪問機制文件訪問分“打開文件”、“讀寫文件”,“關(guān)閉文件”3步,I/O庫中

14、提供的文件訪問函數(shù)很多,現(xiàn)列出常用函數(shù)。見例子代碼14-5(01)fopen():打開一個文件(02)fclose():關(guān)閉一個文件(03)fcloseall():關(guān)閉打開的文件(04)fseek():移動文件指針(09)fprintf():將變量格式化成字符串,寫入到文件中(10)fscanf():從一個文件中讀取格式化的數(shù)據(jù)到變量(05)fgetc()/getc():從文件中讀一個字符(06)fputc()/putc():寫一個字符到文件中(07)fgets():從一個文件中讀取C風(fēng)格字符串(08)fputs():將C風(fēng)格字符串寫入到一個文件(11)getchar():從stdin(鍵盤)

15、讀取一個字符(12)putchar():輸出一個字符到stdout(屏幕)(13)gets():從stdin(鍵盤)讀取一個字符串(14)puts():輸出一個字符串到stdout(屏幕)(15)remove():刪除一個文件14.3 流類庫 前面對高層I/O(C語言的文件操作)做了簡單的介紹,但實際上,C+引入的流類庫比高層I/0更為安全高效,流類庫對輸入、輸出和文件等的操作做了合理的封裝,使得程序的邏輯結(jié)構(gòu)也更清晰。因為絕大多數(shù)的流類庫是模板形式,可實例化為char版本和wchar_t版本,如無特別說明,本節(jié)討論的是char版本的情況,wchar_t版本與此完全一致。14.3.1 流類庫更

16、安全、更高效理解這個標(biāo)題的關(guān)鍵在于“更”字,不可否認(rèn),從C標(biāo)準(zhǔn)庫繼承來的高層I/O也和安全和高效,但為什么說流類庫比高層I/O更安全高效呢,這要從流類庫和高層I/O的機制區(qū)別說起。高層I/O庫函數(shù)主要用來處理基本數(shù)據(jù)類型(字符、整型、浮點數(shù)等),使用參數(shù)表進(jìn)行數(shù)據(jù)傳輸,使用控制字符串指定數(shù)據(jù)類型和輸入輸出格式。它們在運行時對格式字符串進(jìn)行語法分析,并據(jù)此對變量進(jìn)行解釋。雖然printf和scanf族函數(shù)(包括串行版本和文件版本)已經(jīng)被很好地優(yōu)化,但在運行期間進(jìn)行解釋嚴(yán)重依賴于用戶的輸入,稍不留意便可能出現(xiàn)問題,如果能在編譯期間分析格式字符串里的變量,根據(jù)不同的類型調(diào)用各自的函數(shù)處理,會加快運行

17、速度,而且,編譯期間的類型檢查有助于發(fā)現(xiàn)錯誤。流類庫是通過類的繼承、類成員函數(shù)的重載來實現(xiàn)的。因此更易用,更安全,更高效。14.3.2 流類庫層次 iostream庫主要包括如所示的幾個頭文件,在前面所有示例代碼中使用的頭文件便是其中之一。14.3.3 iostream 繼承層次14.4 輸出流 C+將輸入輸出都抽象為字節(jié)流,輸出流ostream類的任務(wù)便是將數(shù)值類型轉(zhuǎn)換為以字符字節(jié)為單位的輸出,這些是通過ostream類的公共方法(接口)來實現(xiàn)的,本節(jié)以標(biāo)準(zhǔn)輸出流對象cout為例來討論。14.4.1 操作符在流類庫中,稱為插入操作符,ostream類中已經(jīng)以成員函數(shù)的形式重載了C+基本類型(

18、如char、int、long、double等)的操作符處理函數(shù),其基本類型為:ostream& operator(基本類型);在前面幾乎所有的示例中都使用了進(jìn)行輸出,舉例來說:cout5;上述輸出整數(shù)5的操作實際上等價于:cout.operator(5); /對應(yīng)的原型為cout.operator(int)操作符的返回類型都為ostream&,這是為了實現(xiàn)鏈?zhǔn)捷敵?,如:cout5”,”6.2;的結(jié)合順序為從左到右,上述代碼等價于:(cout.operatoer(5).operator(“.”).operator(6.2);見示例代碼14-614.4.2 put()、write()、鏈?zhǔn)捷敵?除

19、了操作符外,ostream類中還定義了成員函數(shù)put()和write(),分別用于顯示字符和字符串,其函數(shù)原型分別為:ostream& put(char);ostream& write(const char*,int n); put函數(shù)的參數(shù)指明了要顯示的字符,write函數(shù)的第一個參數(shù)提供了要顯示的字符串的地址,第二個參數(shù)指明了要顯示多少個字符。 因為put函數(shù)和write函數(shù)都返回ostream類對象的引用,因此,put函數(shù)、write函數(shù)和操作符可組成鏈?zhǔn)捷敵?,見示?4-714.4.3 格式狀態(tài)字在ios_base類中定義了用于控制輸入輸出的格式狀態(tài)字,以滿足不同的I/O需求。ostr

20、eam類是從ios類派生而來,而ios類是從ios_base類派生而來,在ios_base類中定義了流的格式信息,以及設(shè)置和讀取這些信息的方法。格式狀態(tài)字是一個32位的long型整數(shù),其每一位都代表了特定的含義。理解格式化常量能更好地理解格式狀態(tài)字,在ios_base類中,維護(hù)了下述枚舉結(jié)構(gòu):14.4.4 格式控制值的默認(rèn)值默認(rèn)情況下,I/O流類庫的格式控制值為:0000 0010 0000 0001第1位為1,即會跳過輸入中的空白,第2位為0代表不會在插入操作后立即刷新緩沖區(qū),第3位為0代表16進(jìn)制如初時,AF和前綴X(如果要輸出前綴的話)大寫,第4位為0代表采用8進(jìn)制和16進(jìn)制時不輸出前綴

21、“0”或“0 x”,第5位為0代表不輸出小數(shù)后無意義的0,第6位為0代表正數(shù)前不會加正號,第7、8、9位為0,代表默認(rèn)情況下C+并不對輸出進(jìn)行對齊,C+將數(shù)據(jù)的正確顯示排在首要位置,而把是否對齊等美觀性的考慮放在第二位,第10位為1,第11、12為0代表在輸出數(shù)據(jù)或接收輸入時,默認(rèn)采用10進(jìn)制的形式,而不是8進(jìn)制或16進(jìn)制的形式,第13、14位為0代表系統(tǒng)的默認(rèn)浮點輸出既不一定恒為定點形式,也不一定恒為浮點數(shù)形式,而是根據(jù)輸出浮點數(shù)的具體情況加以考慮,這在稍后“輸出浮點數(shù)”一節(jié)中會有介紹,第15位為0代表在輸出bool型變量時,默認(rèn)將true輸出為1,將false輸出為0,而不是直接輸出“tr

22、ue”或false。14.4.5 flag()函數(shù)讀取和設(shè)定格式狀態(tài)字 ios_base類中提供了成員函數(shù)flag()來讀取和設(shè)置格式狀態(tài)字,flag()函數(shù)有兩種調(diào)用形式: (1)long flags()無參的flags()函數(shù)調(diào)用返回當(dāng)前格式狀態(tài)字的情況,而不對其做任何的改變,見示例14-8 (2)long flags(long flagNew)這種調(diào)用方式將flagNew以位方式拷貝到格式狀態(tài)字中,這樣實現(xiàn)了對格式狀態(tài)位的操作,返回修改前的格式狀態(tài)字。見示例14-914.4.6 使用setf函數(shù)和unsetf函數(shù)設(shè)定格式關(guān)鍵字flags函數(shù)已經(jīng)可以很好地設(shè)定格式狀態(tài)字,但在設(shè)定前都要讀取

23、當(dāng)前格式狀態(tài)字,變化后采用位復(fù)制的形式修改,對每位進(jìn)行了操作,這似乎有些麻煩,為此,ios_base類中提供了成員函數(shù)setf()和unsetf()來對格式狀態(tài)字的進(jìn)行設(shè)置,與flags函數(shù)的根本不同在于setf函數(shù)和unsetf函數(shù)只對參數(shù)中指定的位進(jìn)行操作,對其他位沒有影響,分別來看一下:(1)一元setf函數(shù),對應(yīng)的原型為:long setf(long lFlag);這種調(diào)用方式返回當(dāng)前格式狀態(tài)字,并根據(jù)lFlag將格式狀態(tài)字的相應(yīng)位設(shè)置為1,使其有效,但不影響所有其它的標(biāo)志位,一元setf函數(shù)實際上等價于:long flags(flags()| lFlag);通俗地說,一元setf函數(shù)

24、將格式狀態(tài)字中與ff中為1的位對應(yīng)的位設(shè)定為1。(2)二元setf函數(shù),對應(yīng)的原型為:long setf(long ffadd, long ffremove);這種調(diào)用方式同樣返回當(dāng)前格式狀態(tài)字,但與一元setf函數(shù)不同之處在于其多了一個參數(shù)ffremove,實際上,二元setf函數(shù)等價于:long flags(flags() & ffremove);long flags(flags() | ffadd);(3) unsetf函數(shù):long unsetf(long ffremove); 其含義和setf()相反,根據(jù)ffremove將格式控制字的對應(yīng)位設(shè)置為0,使其失效。見示例14-1014.

25、4.7 設(shè)置域?qū)捰驅(qū)捠怯脕砜刂戚敵龅?,在ios類中用int型變量x_width存放,對域?qū)掃M(jìn)行操作的函數(shù)有兩個:(1)int width()此函數(shù)是用來返回當(dāng)前的域?qū)捴?,它的函?shù)實現(xiàn)為:int ios_base:width()return x_width;(2)int width(int wid)此函數(shù)用來設(shè)置域?qū)?,并返回原來的域?qū)?,具體函數(shù)定義為:int ios_base:width(int wid)int i=x_width;x_width=wid;return i;見代碼14-1114.4.8 填充字符 從代碼14-11已經(jīng)看到,C+默認(rèn)用空格填充顯示時不足域?qū)挼牟糠?,ios_base類

26、還提供了成員函數(shù)fill以指定其他的填充符,其格式為:char ios_base:fill(); /返回當(dāng)前填充符char ios_base:fill(char ch);/將ch作為新的填充符,并返回原來的填充符 和width函數(shù)指定域?qū)挕耙淮斡行А辈煌氖?,新的填充字符將一直有效,采用fill函數(shù)指定新的填充字符。示例14-1214.4.9 浮點數(shù)輸出和顯示精度默認(rèn)情況下,C+采用前面printf函數(shù)g說明符的格式,6位有效數(shù)字,不輸出無意義的0。此外,ios_base類還定義了fixed(定點計數(shù)法)和scientific(科學(xué)計數(shù)法)兩種輸出模式,其中fixed意味著不管數(shù)字長度如何,使

27、用格式567.89表示浮點值,而scientific意味著恒使用5.6789+e002形式,如果兩個標(biāo)志位均為0,采用默認(rèn)形式。如果不指定精度,fixed和scientific都默認(rèn)為6位小數(shù),但可以使用ios_base類提供的precision函數(shù)指定浮點數(shù)的小數(shù)位數(shù),precision函數(shù)同樣有兩種調(diào)用形式:int ios_base:precisioin();/返回當(dāng)前精度int ios_base:precision(int n);/設(shè)置當(dāng)前精度為n,并返回原來的精度和fill函數(shù)一直,precision函數(shù)同樣一直有效,直到有新的精度值并設(shè)定,但要特別注意的是,precision函數(shù)的精

28、度設(shè)定影響的僅僅是浮點型數(shù)據(jù),對整型數(shù)據(jù)或其他類型沒有影響。見示例代碼14-1314.4.10 控制符在使用ios_base類的setf函數(shù)時,需要對參數(shù)有足夠的了解,不夠友好,為此,C+流類庫在頭文件中提供了多個控制符,由控制符完成setf函數(shù)的調(diào)用,這些控制符有(含*的為默認(rèn)):boolapha *noboolapha showbase *noshowbase showpoint *noshowpoint showpos *noshowpos *skipws noskipws uppercase *nouppercase *dec hex oct left right internal *

29、fixed scientific flush ends endl wssetfill(ch) setprecision(n) setw(n) setbase(b) setioflags(n) resetioflags(n)無參控制符實際上是函數(shù),其原型為:ios_base& 控制符(ios_base&);舉例來說:boolalpha(cout);/等價于out.setf(ios_bse:boolalpha)couttrueendl;由于ostream類重載了操作符,則下面的1句等價于上面的2句:coutboolalphatrue說起。14.5.1 操作符在流類庫中,稱為抽取操作符,istrea

30、m類中已經(jīng)以成員函數(shù)的形式重載了C+基本類型(如char、int、long、double等)的操作符處理函數(shù),其基本類型為:istream& operator(基本類型&);在前面的示例代碼中曾使用通過鍵盤對基本類型變量賦值,舉例來說:int x=0; cinx;等價于cin.operator(x);/對應(yīng)原型為cout.operator(int &)通過傳遞引用的方式,保證了抽取操作處理的變量x自身,而不是像傳值操作那樣處理其副本,因此,cin能直接修改作為參數(shù)的變量的值。支持鏈?zhǔn)捷斎?,如:double x; int y; char z10;cin x y z;14.5.2 輸入流與格式狀態(tài)

31、字在前面提到的格式狀態(tài)字中,只有4項是和輸入有關(guān)的,分別為:skipws = 0 x0001, /in,跳過輸入中的空白dec= 0 x0200, /input&output,轉(zhuǎn)換為10進(jìn)制oct= 0 x0400, /input&output,轉(zhuǎn)換為8進(jìn)制hex= 0 x0800, /input&output,轉(zhuǎn)換為16進(jìn)制(1)skipwscinnoskipws;設(shè)置不跳過空白符,cin.sync()類似于fflush(stdin),會清空緩沖區(qū)。見代碼14-15(2)dec、oct和hexcinhex;會將輸入設(shè)置成16進(jìn)制,見代碼14-1614.5.3 輸入流與域?qū)抜ostream類中

32、定義的成員函數(shù),如width()、fill()、precsion,以及iomanip中定義的一些有參控制符,如setfill()、setw()、setprecision等,都適用于輸入流,但實際只有少數(shù)幾個真正能影響輸入流對象,本節(jié)討論一個使用最多的用法:字符數(shù)組與域?qū)捲趯har型數(shù)組進(jìn)行輸入時,一個重要的問題是保證輸入字符串的長度小于數(shù)組的大小。流類庫提供了width()函數(shù)和setw控制符,用于限定輸入的字符個數(shù):cin.width(n);/設(shè)置最多讀入n-1個字符。最后一個要放0。setw(n); /與cin.width(n)等價。和cout.width(n)一樣,cin的域?qū)捲O(shè)置也是

33、一次有效。長于域?qū)挼妮斎霑唤財?,剩下的輸入仍然遺留在緩沖區(qū)中。見代碼14-17:14.5.4 使用get函數(shù)讀取單個字符(1)以前我們曾使用get函數(shù)和getline函數(shù)讀取一行字符的操作,這些函數(shù)稱為非格式化函數(shù),這些函數(shù)讀取字符輸入(包括空格),不進(jìn)行數(shù)據(jù)轉(zhuǎn)換。本節(jié)討論如何使用iostream類的get成員函數(shù)讀取單個字符。(1)istream& istream:get(char &c);此函數(shù)調(diào)用將待賦值char型變量作為其參數(shù),返回的istream類的引用,所以可以將其拼接起來,即下列用法是合法的:char c1,c2,c3;cin.get(c1).get(c2).get(c3);/

34、或者cin.get(c1).get(c2)c3;get()函數(shù)不會跳過任何空白回車換行符。而cin則可能會跳過,要看skipws的設(shè)置。見代碼14-1814.5.4 使用get函數(shù)讀取單個字符(2) (2)int istream:get(void)該函數(shù)調(diào)用讀入一個字符(包括空白字符),并返回該字符的整型值,和上面有參get版本不同,因返回值并非istream類的對象,因此,無法將多個無參get函數(shù)拼接起來,基本的用法為:char c1cin.get(); 代碼14-19完成和14-18同樣的功能。14.5.5 使用get和getline函數(shù)讀取C風(fēng)格字符串istream類中重載了get函數(shù)和

35、getline函數(shù)來一次性讀取多個字符到C風(fēng)格字符串中,大致有以下重載版本:(1)istream& istream:get(char *buffer, int size,char delim=n )get結(jié)束的條件有2個:達(dá)到最大字符數(shù)size-1或碰到指定的結(jié)束符(默認(rèn)為n)見代碼14-20(2)istream& istream:getline(char *buffer, int size,char delim=n)getline()和get()幾乎完全一致,不同在于對分隔符的處理上:get()將分隔符遺留在輸入流中, 而getline()會抽取并丟棄分隔符,getline()也不會將分隔符

36、讀取到字符串變量中.見代碼14-2114.5.6 其他istream方法除了get函數(shù)和getline函數(shù),istream類中還定義了包括ignore()、read()、peek()、gcount()和putback()等成員函數(shù),本節(jié)簡要對它們的用法作一下介紹:(1)ignore函數(shù):istream & istream:ignore(int n=1,int delim=EOF);從輸入流中抽取n個字符丟棄,停止條件是達(dá)到n個字符或碰到分隔符.見代碼14-22(2)read函數(shù): istream & istream:read(char* buf,int n);讀取n個字符到buf中,與getl

37、ine和get不同的是,read不會在輸入后自動加入0(3)peek函數(shù): int istream:peek();返回輸入流中下一個字符的int值,但并不將其從輸入流中抽取出來。EOF(4)gcount函數(shù): int istream:gcount()返回最后一個非格式化抽取方法讀取的字符數(shù),這些函數(shù)有g(shù)et, getline, ignore和read,不包括操作符,因為對輸入進(jìn)行了格式化。(5)putback函數(shù): istream& istream:putback(char);將一個字符插入到輸入緩沖區(qū)的頭部(下一個要去的位置),并返回istream類對象的引用。實際上peek相當(dāng)于是先用ge

38、t函數(shù)讀取一個字符,再將該字符putback回去。14.6 流狀態(tài) 每個流(istream或osream)都有一個與之相關(guān)的狀態(tài)字,出錯和非標(biāo)準(zhǔn)條件都通過適當(dāng)?shù)卦O(shè)置和檢測這個狀態(tài)字來處理。14.6.1 什么是流狀態(tài)ios_base類中定義了如下枚舉結(jié)構(gòu),用以表示流的狀態(tài)。enum Iostate goodbit = 0 x0, /沒有位設(shè)置,操作正常eofbit = 0 x1,/到達(dá)流末尾failbit = 0 x2, /I/O操作失敗,如未能取得預(yù)期字符,badbit = 0 x4,/非法操作_Statmask = 0 x7;不難看出,eofbit、failbit和badbit狀態(tài)常量實際上

39、分別對應(yīng)著狀態(tài)字的第1,2,3位,當(dāng)輸入輸出流出現(xiàn)各種問題時,會自動置eofbit、failbit和badbit中的一個或多個有效,也就是將其在狀態(tài)字中的對應(yīng)位置1。只有當(dāng)3位都為0,即狀態(tài)字等于goodbit時,才說明一切正常,程序可以使用ios_base提供的共用成員函數(shù)檢查和設(shè)置流的狀態(tài),決定要進(jìn)行的操作。14.6.2 讀取流狀態(tài) ios_base類提供了如下函數(shù)讀取當(dāng)前的流狀態(tài),如14-8所示: 見代碼14-2314.6.3 管理流狀態(tài)對流狀態(tài)的管理可分為狀態(tài)字的設(shè)置和緩沖區(qū)管理兩部分:(1)設(shè)置狀態(tài)字ios_base類中提供了clear函數(shù)和setstate函數(shù)用來設(shè)置狀態(tài)。clea

40、r函數(shù)的原型為:void ios_base:clear( int nState = 0 );如果參數(shù)為0,該函數(shù)將清除所有錯誤標(biāo)志,否則,參數(shù)可以設(shè)置為goodbit、eofbit、failbit、badbit中的一種或者它們的組合,clear函數(shù)首先將所有的標(biāo)志清除,然后將參數(shù)指定的標(biāo)志置位。setstate函數(shù)的原型為:void ios_base:setstate( int nState );代碼見14-24(2)管理緩沖區(qū) 在某些情況下,僅僅將流狀態(tài)字復(fù)位還不夠,因為導(dǎo)致匹配失敗、錯誤發(fā)生的輸入仍殘留在緩沖區(qū)中,程序必須將其從緩沖區(qū)中提取出來,跳過這些輸入字符,這類方法很多,前面介紹的諸

41、如ignore函數(shù),get函數(shù)等都可以滿足要求。這里特別推薦一個sync函數(shù),其調(diào)用格式為:int sync(); cin.sync(); /fflush(stdin);14.7 重載和 前面提及,和高層I/O相比,流類庫的一大優(yōu)勢在于可以對輸入輸出進(jìn)行擴展,以滿足自定義類型和結(jié)構(gòu)的需要,本節(jié)給出插入符的使用范例。14.7.1 插入符的重載 在ostream類中定義的操作符是作為成員方式重載的,舉例來說:cout5; 等價于:cout.operator(5); 對自定義類型來說,重載操作符的重載 和插入符,同樣有3個要求:以友元函數(shù)形式進(jìn)行。第一參數(shù)是istream類的引用,第二個參數(shù)是自定義

42、類型的引用。返回istream類的引用以實現(xiàn)鏈?zhǔn)匠槿?,即拼接抽取?仍以中定義的Complex類為例,為其重載抽取符,見代碼14-26。14.8 文件操作 前面已經(jīng)提到,RAM中存儲的內(nèi)容在掉電后會自動消失,可有些信息在下次通電開機時可能會用到,文件可以有效解決這一問題,文件本身是存儲在某種設(shè)備(硬盤、光盤、軟盤和磁帶等)上的一系列字節(jié),流類庫處理文件的機制和標(biāo)準(zhǔn)輸入輸出機制幾乎完全一樣,文件也被看成是一種“流”,要寫入文件,可以通過創(chuàng)建ofstream類對象,并使用其類內(nèi)方法,如write函數(shù)或操作符來完成。14.8.1 文件操作基本過程在C+中,要進(jìn)行文件的輸入輸出,必須首先創(chuàng)建一個流,然

43、后將這個流與文件相關(guān)聯(lián),即打開文件,此時才能進(jìn)行讀寫操作,完成后再關(guān)閉這個文件。這就是C+中進(jìn)行文件輸入輸出的基本過程C+有3種類型的文件流:輸入文件流ifstream,輸出文件流ofstream,輸入輸出文件流fstream。這些文件流類都定義在fstream文件中,因此,在使用3種流對象之前,需要包含頭文件。實際上,ifstream是從istream繼承而來,ofstream是從ostream繼承而來,而fstream是從iostream繼承而來,也就是說,前面所講的輸入輸出流的機制,如各種插入符的定義、格式化方法、控制符和流狀態(tài)等同樣適用于文件操作,同時,為了滿足文件操作的特殊要求,在派

44、生類中增加了一些針對文件的處理函數(shù)。實際上,ifstream、ofstream和fstream也分別是模板類basic_ifstream、basic_ofstream和basic_fstream的實例化對象。14.8.2 文件的打開在C+中,打開一個文件,就是建立一個文件輸入輸出流,并將文件和流關(guān)聯(lián)起來,而關(guān)閉一個文件,就是取消這種關(guān)聯(lián),首先來看以下流的建立過程:建立流的過程就是定義流類的對象,例如:ifstream in;ofstream out;fstream io;上述代碼分別定義了輸入流對象in、輸出流對象out和輸入輸出流對象io。接下來,需要將流對象和特定的文件關(guān)聯(lián)起來,使用ope

45、n()函數(shù)打開文件是一種常用的方法,open()函數(shù)的原型是在fstream中定義的,在ifstream,ofstream和fstream類中均有實現(xiàn),其原型為:void open(const char *,ios_base:openmode);14.8.3 取消文件和流的關(guān)聯(lián) 當(dāng)流對象生命期結(jié)束,被撤銷時,該對象和文件的關(guān)聯(lián)會自動斷開。此外,C+還提供了close函數(shù)來顯式斷開文件和流的連接,如:logfile.close();/假定logfile為ostream類對象 注意,close操作僅僅是斷開了文件和流的連接,流對象并不會被撤銷,流緩沖區(qū)中的數(shù)據(jù)也會被保留,這個流還可以關(guān)聯(lián)到其他的文

46、件上 來看一個簡單的示例14-2714.8.4 文件的讀寫文件分為文本文件和二進(jìn)制文件,前者以字節(jié) (byte )為單位,每字節(jié)對應(yīng)一個ASCII 碼,表示一個字符,故又稱字符文件。二進(jìn)制文件以字位(bit )為單位,實際上是由0和1組成的序列。例如float型值3.141592以文本形式存儲占用8個字節(jié),即每位數(shù)字都對應(yīng)一個字符,這需要將float型數(shù)的機內(nèi)表示轉(zhuǎn)換為字符格式,以二進(jìn)制形式存儲則可能只占用4個字節(jié),即存儲的是該float型值的機內(nèi)表示。對文件的讀寫也分為按文本(text)方式和按二進(jìn)制(binary)方式兩種,兩者的特點對比見下表:14.8.5 文本文件的讀寫 文本文件的讀寫

47、和前面介紹的輸入流和輸出流用法幾乎完全一致,所不同的是,將cout和cin等標(biāo)準(zhǔn)輸入輸出流替換成了ofstream類和ifstream類對象,面向的設(shè)備也成了文本文件. 來看一段例子14-2814.8.6 二進(jìn)制文件的讀寫 讀寫二進(jìn)制文件,一般使用成員函數(shù)read()和write()成員函數(shù),它們原型如下:read(unsigned char *buf,int num);write(const unsigned char *buf,int num); read()從文件中讀取 num 個字符到 buf 指向的緩存中,如果在還未讀入 num 個字符時就到了文件尾,可以用成員函數(shù) int gcou

48、nt();來取得實際讀取的字符數(shù);而 write()從buf 指向的緩存寫 num 個字符到文件中,值得注意的是緩存的類型是 unsigned char *,有時可能需要類型轉(zhuǎn)換。 見例子14-2914.8.7 文件定位指針和隨機讀取每個流(不僅僅是文件流,也包括普通流)都隱含著一個指針,對文件來說,C+把每一個文件都看成一個有序的字節(jié)流,如所示,每一個文件或者以文件結(jié)束符(end of file marker)結(jié)束,或者在特定的字節(jié)號處結(jié)束。pos_type tellg():獲取當(dāng)前get流指針的位置pos_type tellp():獲取當(dāng)前put流指針的位置void seekg(pos_t

49、ype pos):設(shè)置get流到指定位置void seekp(pos_type pos):設(shè)置put流到指定位置void seekg(off_type offset, seekdir dir):設(shè)置get流到相對位置void seekp(off_type offset, seekdir dir):設(shè)置put流到相對位置enum seekdir beg = 0, cur = 1, end = 2見代碼14-3014.9 字符串流 C+庫中提供了非模板類strstream和模板類sstream,用以處理字符串的輸入輸出 strstream類用于讀取字符數(shù)組的格式化信息并將格式化信息寫入字符數(shù)組,也就是說,strstream類以字符數(shù)組為輸入輸出設(shè)備 sstream類用于讀取string對象中的格式化信息并將格式化信息寫入string對象,也就是說,sstream類以string對象作為輸入輸出設(shè)備。 新的C+標(biāo)準(zhǔn)已經(jīng)指出,除非出

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論