版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、第八章 C+ 的 I/O 流庫,C+ 為什麼要建立自己的輸入輸出系統(tǒng)? 1 C 雖然具有一個(gè)靈活和功能強(qiáng)大的輸入輸出系統(tǒng), 但它并不支持自定義類型。例如: class account char name30; double balance; public: account(); account(char*, double); ;, account acnt; scanf(“%account”, / 錯(cuò)誤,不支持 account 類型 因?yàn)檩斎牒瘮?shù) scanf 和輸出函數(shù) printf 的格式串形參 只能與系統(tǒng)預(yù)定義類型匹配,而無法識(shí)別用戶的自 定義類型,并且也不能通過重載定義 scanf 和
2、printf 函數(shù)的新版本,使它們的格式串形參能匹配任意用 戶自定義類型。,2 面向?qū)ο蟪绦蛟O(shè)計(jì)必須定義眾多的用戶自定義類, 如何以面向?qū)ο蟮脑O(shè)計(jì)原則和方法為自定義類設(shè)計(jì) 既規(guī)格統(tǒng)一,又適應(yīng)個(gè)性化的輸入輸出操作行為是 十分必要的。因此 C+ 必須建立一個(gè)能通過對(duì)輸入 輸出操作重載的方法實(shí)現(xiàn)對(duì)任意自定義類型對(duì)象輸 入輸出支持的系統(tǒng)。,本章要點(diǎn) 1 C+ 流庫結(jié)構(gòu) 流庫的概念、流庫的組成。 2 標(biāo)準(zhǔn)輸入輸出流 輸入輸出流類的定義、輸入輸出運(yùn)算符、輸入輸出 的格式控制。 3 自定義類的輸入輸出 輸入輸出運(yùn)算符的重載。 4 文件的輸入輸出流 文件的打開、關(guān)閉和讀寫。 5使用 MFC 的對(duì)話框類實(shí)現(xiàn)輸入
3、輸出,8.1 C+ 流庫結(jié)構(gòu) 8.1.1 流庫的概念 流(stream)是從源(數(shù)據(jù)的生產(chǎn)者)到目標(biāo)(數(shù) 據(jù)的使用者)被傳輸數(shù)據(jù)的引用。每個(gè)流都是一個(gè)與 某種數(shù)據(jù)傳輸設(shè)備相關(guān)聯(lián)的對(duì)象。 流具有方向性: 輸入流是與輸入設(shè)備(如鍵盤)關(guān)聯(lián)的流。 輸出流是與輸出設(shè)備(如顯示器屏幕)關(guān)聯(lián)的流。 輸入輸出流是與輸入輸出設(shè)備(如磁盤)關(guān)聯(lián)的流。,C+ 中包含的預(yù)定義流: cin 輸入流,與輸入設(shè)備關(guān)聯(lián)。 cout 輸出流,與輸出設(shè)備關(guān)聯(lián)。 cerr 非緩沖型錯(cuò)誤信息流,與錯(cuò)誤輸出設(shè)備關(guān)聯(lián); clog 緩沖型錯(cuò)誤信息流,與錯(cuò)誤輸出設(shè)備關(guān)聯(lián)。 在缺省情況下,指定的輸入設(shè)備是控制臺(tái)鍵盤,輸 出設(shè)備是控制臺(tái)顯示器
4、終端。在任何情況下,指定的 錯(cuò)誤輸出設(shè)備總是控制臺(tái)顯示器終端。,cin 和 cout 的使用方法我們已經(jīng)很熟悉了。cerr 和 clog 均是用來輸出錯(cuò)誤信息,它們的使用方法與 cout 基本相同,只不過它們所關(guān)聯(lián)的設(shè)備始終是控制臺(tái)顯 示器,而不隨著 cout 關(guān)聯(lián)設(shè)備的改變而變化。cerr 和 clog 之間的區(qū)別是: cerr 對(duì)輸出的錯(cuò)誤信息不緩沖,因而發(fā)送給它的任何內(nèi) 容都立即輸出。 clog 輸出的錯(cuò)誤信息被緩沖,當(dāng)緩沖區(qū)滿時(shí)才進(jìn)行輸 出,也可以通過刷新流的方式(遇到操縱符 endl 或 flush)強(qiáng)迫刷新緩沖區(qū)導(dǎo)致顯示輸出。,下面給出一段使用預(yù)定義輸入輸出流信息的程序: cout
5、 sales; cout num; if (num = 0) cerr The average can not be computed.n; else avgsales = sales / num; cout The average selling price per nuit was ; cout avgsales n; ,C+ 流庫是用面向?qū)ο蟮脑O(shè)計(jì)方法建立起來的輸入 輸出類庫,它具有兩個(gè)平行的根基類 streambuf 和 ios, 庫中所有其他的類均從它們直接或間接派生。系統(tǒng)中 預(yù)定義流,cin、cout、cerr、clog 都是流庫中相應(yīng)類的 對(duì)象。,8.1.2 streambuf
6、類 streambuf 類是流庫的根基類,它為輸入輸出物理設(shè) 備提供緩沖區(qū)和流處理的一些通用方法。 C+ 將輸入輸出流均視為字節(jié)流,因此緩沖區(qū)是由 一個(gè)字符串和兩個(gè)指針組成的。這兩個(gè)指針分別指 向數(shù)據(jù)流在輸入緩沖區(qū)中的插入位置和在輸出緩沖 區(qū)的提取位置。 streambuf 類提供對(duì)緩沖區(qū)的底層操作,例如設(shè)置緩 沖區(qū)、對(duì)緩沖區(qū)指針進(jìn)行操作、從緩沖區(qū)取字節(jié)、向 緩沖區(qū)存儲(chǔ)字節(jié)等。streambuf 類有三個(gè)派生類,filebuf 類、strstreambuf 類和 conbuf 類。它們的派生層次關(guān)系 如圖所示:, filebuf 類擴(kuò)展了 streambuf 類的功能,用于文件流與 文件緩沖區(qū)
7、相關(guān)聯(lián),實(shí)現(xiàn)對(duì)文件緩沖區(qū)中的字節(jié)序 列的讀寫操作: 寫文件:緩沖區(qū)內(nèi)容按字節(jié)寫到指定的文件中, 然后刷新緩沖區(qū)。 讀文件:指定文件內(nèi)容按字節(jié)讀到緩沖區(qū)中。 打開文件:filebuf 與被讀或?qū)懙奈募嚓P(guān)聯(lián)。,streambuf, 關(guān)閉文件:filebuf 與被讀或?qū)懙奈募獬P(guān)聯(lián)。 strstreambuf 類擴(kuò)展了 streambuf 類的功能,提供了將 內(nèi)存作為輸入輸出設(shè)備時(shí),進(jìn)行提取和插入操作的 緩沖區(qū)管理。 conbuf 類擴(kuò)展了 streambuf 類的功能,用于控制臺(tái)顯 示器輸出緩沖區(qū)關(guān)聯(lián)和管理,提供光標(biāo)控制、顏色 設(shè)置、活動(dòng)窗口定義、清屏、行清除等屏幕控制功 能(注意,這些屏幕控
8、制功能在有些編譯器版本中 不提供,例如 visual C+)。 通常情況下,對(duì)設(shè)備緩沖區(qū)的操作一般使用上述三 個(gè)派生類,很少直接使用基類 streambuf。,8.1.3 ios 類 ios 類及其派生類為用戶提供使用流的接口,該類具 有一個(gè) streambuf 類型指針指向流的緩沖區(qū)。ios 類及其 派生類對(duì)象通過該指針使用 streambuf 及其派生類對(duì)象 完成輸入輸出時(shí)的格式化或非格式化轉(zhuǎn)換,并檢查輸 入輸出的錯(cuò)誤。ios 是流庫中的另一個(gè)根基類,它有四 個(gè)直接派生類: 輸入流類 istream: class istream : virtual public ios; 輸出流類 ost
9、ream: class ostream : virtual public ios;, 文件流類 fstreambase: class fstreambase : virtual public ios; 字符串流類 strstreambase: class strstreambase : virtual public ios; 這四個(gè)派生類成為流類庫中的基本流類,它們又組 合派生出以下的流類: 輸入文件流類 ifstream: class ifstream : public istream, public fstreambase; 輸入字符串流類 istrstream: class istrst
10、ream : public istream, public strstreambase; 輸出文件流類 ofstream: class ofstream : public ostream, public fstreambase;, 輸出字符串流類 ostrstream: class ostrstream : public ostream, public strstreambase; 控制臺(tái)輸出流類 constream: class constream : public ostream; 輸入輸出流類 iostream: class iostream : public istream, publ
11、ic ostream; 輸入輸出文件流類 fstream: class fstream : public iostream, public fstreambase; 輸入輸出字符串流類 strstream: class strstream : public iostream, public strstreambase;,從上述的 istream、ostream 和 iostream 又分別派生出 具有賦值運(yùn)算符“=”重載的新類: 帶賦值的輸入流類 istream_withassign: class istream_withassign : public istream; 帶賦值的輸出流類 os
12、tream_withassign: class ostream_withassign : public ostream; 帶賦值的輸入輸出流類 iostream_withassign: class iostream_withassign : public iostream; 上述流類的派生層次結(jié)構(gòu)如下圖所示。,ios,系統(tǒng)預(yù)定義流 cin、cout、cerr 和 clog 在系統(tǒng)頭文件 iostream.h 中被定義: extern _CRTIMP istream_withassign cin; extern ostream_withassign _CRTIMP cout; extern os
13、tream_withassign _CRTIMP cerr; extern ostream_withassign _CRTIMP clog; 顯然,用戶也可以用 istream 和 ostream 等流類定義 自己的流對(duì)象,例如:istream is;ostream os; 對(duì)預(yù)定義類型數(shù)據(jù)的輸入輸出操作已經(jīng)定義為流類 的操作,而對(duì)用戶自定義類型對(duì)象的輸入輸出操作則 可以通過重載運(yùn)算符 “”和“” 得以實(shí)現(xiàn)。,Java 的 I/O 流類在構(gòu)造和使用上與 C+ 有一些有趣 的差別: 1 C+ 的 I/O 流類庫是把所有的輸入輸出功能封裝在 數(shù)量相對(duì)較少的幾個(gè)流類中,自定義類則是通過重 載機(jī)制使得
14、流類對(duì)象能夠?qū)ψ远x類對(duì)象進(jìn)行輸入 輸出操作。 而 Java 則幾乎為每一種情況提供了一個(gè)獨(dú)立的類。 例如,底層的字節(jié)流操作類、按數(shù)據(jù)類型劃分的各 種高級(jí)操作類,對(duì)底層 I/O 包裝后進(jìn)行某種特定操 作(如 Unicode 讀寫)的類,隨機(jī)讀寫操作類,數(shù) 組讀寫類等等。,2 C+ 的流在缺省情況下是進(jìn)行緩沖的,但 Java 的流 在缺省情況下是不緩沖的。但可以調(diào)用提供了緩沖 功能的類對(duì)一個(gè) Java 的流進(jìn)行緩沖。 3 在 Java 中,所有的整數(shù)和浮點(diǎn)數(shù)都是以大端字節(jié)順 序進(jìn)行輸入輸出的,與底層平臺(tái)無關(guān)。這與 C+ 中 的情況不同,因此 Java 所產(chǎn)生的數(shù)據(jù)文件的可移植 性更高。,4 在典
15、型的 C+ 程序中,字符均使用 ASCII 編碼形式 表示(無論是單獨(dú)使用的字符還是字符串中的字 符)。這與字符從輸入設(shè)備讀入或?qū)懙捷敵鲈O(shè)備都 保持 ASCII 編碼形式是一致的。 一個(gè)典型的 Java 程序中,字符始終是用兩個(gè)字節(jié)的 Unicode 形式表示的。當(dāng)從輸入設(shè)備讀入 ASCII 編碼 形式的字符時(shí),必須先轉(zhuǎn)換為 Unicode 形式后再寫 入內(nèi)存;當(dāng)將 Unicode 形式字符寫到輸出設(shè)備時(shí), 必須先轉(zhuǎn)換為 ASCII 編碼形式后再寫入輸出設(shè)備。 Java 的流類的層次結(jié)構(gòu)如下圖所示:,OutputStream,InputStream,返回,Writer,Reader,8.2 標(biāo)
16、準(zhǔn)輸入輸出流 8.2.1 輸入輸出流類定義 istream 類和 ostream 類在流庫中分別提供基本的標(biāo) 準(zhǔn)輸入輸出操作,是使用流庫的主要接口,在系統(tǒng)頭 文件 iostream.h 中,它們的類定義分別如下: class istream:virtual public ios public: istream(streambuf*);/構(gòu)造函數(shù) / 從輸入流中將字符讀取到給定指針 char* 指向的內(nèi)存,直 / 至遇到分界符、文件結(jié)束符或讀至(len-1)個(gè)字符為止。 istream,/ 從輸入流讀取字符到給定的 streambuf,直至遇到分界符。 istream,/ 從讀入流讀取給定數(shù)目的
17、字符到 char* 指向的內(nèi)存空間。 / 如果發(fā)生錯(cuò)誤時(shí),getcount 函數(shù)可得到實(shí)際讀入的數(shù)目。 istream,/ 按給定偏移 streamoff ( typedef long streamoff)移動(dòng)輸入 / 文件指針,指示偏移方向的枚舉值 ios:seek_dir 的取值: / beg = 從文件開始;cur = 從當(dāng)前位置;end = 從文件尾。 istream /對(duì)系統(tǒng)所有的預(yù)定義類型都給出了的重載定義。 ;,class ostream:virtual public ios public: ostream(streambuf*);/ 構(gòu)造函數(shù) ostream,streampos
18、 tellp(); / 返回輸出流中當(dāng)前指針位置。 / 可重載的輸出運(yùn)算符 ostream,8.2.2 輸入輸出運(yùn)算符的使用 8.2.3 格式控制的輸入輸出 輸入輸出的格式控制可以使得人機(jī)交互界面更加友 好、美觀。在 C 程序中,輸入輸出是使用 C 運(yùn)行庫的 scanf 和 printf 函數(shù)完成的,輸入輸出的格式是通過這兩 個(gè)函數(shù)的格式描述串參數(shù)控制的。在 C+ 程序中,雖 仍然可以使用 scanf 和 printf 函數(shù),但在面向?qū)ο蟮某?序設(shè)計(jì)中,輸入輸出是使用流類庫中的輸入輸出流完 成的,因此輸入輸出的格式控制必須使用流類庫提供 的格式控制的方法: 使用 ios 類的格式控制成員函數(shù);
19、 使用被稱為格式操縱符的特殊函數(shù)。,1 用 ios 類成員函數(shù)進(jìn)行輸入輸出格式化 ios 類提供了用于輸入輸出格式控制的成員函數(shù)。 這些函數(shù)進(jìn)行格式控制的方法是修改以下屬性: 格式標(biāo)志屬性 x_flags:標(biāo)志的不同狀態(tài)值指定輸 入輸出數(shù)據(jù)的不同格式(如對(duì)齊規(guī)則、數(shù)值轉(zhuǎn)換 基、數(shù)字表示規(guī)則等)。 輸出域?qū)拰傩?x_width: 指定輸出數(shù)據(jù)所占顯示 區(qū)域的寬度。 填充字符屬性 x_fill:指定輸出顯示域中數(shù)據(jù)為占 空間的填充字符; 輸出精度屬性 x_precision:指定浮點(diǎn)數(shù)輸出的小 數(shù)部分顯示位數(shù)。, 格式標(biāo)志 C+ 中每個(gè)流對(duì)象的輸入輸出格式都是依據(jù)指定 格式進(jìn)行的,也就是說,流對(duì)象
20、的每次輸入“” 操作是按照當(dāng)前格式標(biāo)志 x_flags 中 的格式狀態(tài)完成的。該屬性是一個(gè) protected 成 員,在類外訪問該屬性是通過公有的格式控制成 員函數(shù)實(shí)現(xiàn)的。注意,該屬性可以在 ios 的派生 類內(nèi)被訪問。為了便于提供格式控制成員函數(shù)的 參數(shù)和參數(shù)具有良好的可讀性,ios 類定義了一 個(gè)公有的無名枚舉數(shù)據(jù)成員,用戶可以使用這些 特定的枚舉元素,形成所需要的格式狀態(tài)傳遞給 相應(yīng)的格式控制成員函數(shù)。,class _CRTIMP ios public: enum skipws = 0 x0001, / 跳過輸入中的空白,用于輸入 left = 0 x0002, / 左對(duì)齊輸出,用于輸
21、出 right = 0 x0004, / 右對(duì)齊輸出,用于輸出 internal = 0 x0008, / 符號(hào)或基數(shù)指示符與數(shù)字之間添加填充符,用于輸出 dec = 0 x0010, / 基數(shù)為 10 進(jìn)制,用于輸入輸出 oct = 0 x0020, / 基數(shù)為 8 進(jìn)制,用于輸入輸出 hex = 0 x0040, / 基數(shù)為 16 進(jìn)制,用于輸入輸出,showbase = 0 x0080, / 顯示基數(shù)指示符,用于輸出 showpoint = 0 x0100, / 顯示小數(shù)點(diǎn),用于輸出 uppercase = 0 x0200, / 16 進(jìn)制輸出時(shí),數(shù)基指示符和 / 數(shù)值中的字母一律為大寫
22、,用于輸出 showpos = 0 x0400, / 正數(shù)前顯示+符號(hào),用于輸出 scientific = 0 x0800, / 科學(xué)表示法浮點(diǎn)數(shù),用于輸出 fixed = 0 x1000, / 定點(diǎn)形式顯示浮點(diǎn)數(shù),用于輸出 unitbuf = 0 x2000, /輸出后立即刷新流,用于輸出。 stdio = 0 x4000, / 刷新 stdout 和 stderr,用于輸出。 ; inline long flags() const;/ 返回當(dāng)前格式標(biāo)志。,inline long flags(long _l); / 設(shè)置指定格式 _l,返回原有格式。 inline long setf(lon
23、g _f, long _m); / 依據(jù)掩碼 _m 設(shè)置指定格式 _f,返回原有格式。inline long unsetf(long _l); / 清除指定格式 _l,并返回原有標(biāo)志。 inline int width() const;/ 返回當(dāng)前域?qū)捴怠?inline int width(int _i); / 設(shè)置指定域?qū)?_i,并返回原有域?qū)捴怠?inline ostream* tie(ostream* _os); / 將流連接到_os 指向輸出流,并返回原來的流指針。 inline ostream* tie() const;/ 返回原來的流指針。,inline fill() const;
24、/ 返回當(dāng)前填充字符。 inline char fill(char _c); / 設(shè)置指定填充字符,并返回原有填充字符。 inline int precision(int _i); / 設(shè)置指定浮點(diǎn)數(shù)精度,并返回原有浮點(diǎn)數(shù)精度。 inline int precision() const;/ 返回當(dāng)前的浮點(diǎn)數(shù)精度。 inline int rdstate() const;/ 返回當(dāng)前的錯(cuò)誤狀態(tài)。 inline void clear(int _i = 0); / 根據(jù)掩碼 _i 設(shè)置或清除錯(cuò)誤狀態(tài)位。 protected: ,long x_flags; int x_precision; char x
25、_fill; int x_width; ;,格式枚舉元素值有一個(gè)共同的特點(diǎn),即使用不同 位為 1 二進(jìn)制數(shù)表示不同的格式值,也就是說, 枚舉元素值的二進(jìn)制表示只有一位為 1。例如: skipws0 x0001: 0000 0000 0000 0001 left0 x0002: 0000 0000 0000 0010 right0 x0004: 0000 0000 0000 0100 顯然,所需要的特定格式標(biāo)志將可以是一個(gè)枚舉 元素值或幾個(gè)的枚舉元素進(jìn)行或運(yùn)算組合而成, 例如,欲設(shè)置左對(duì)齊 10 進(jìn)制科學(xué)表示法顯示浮 點(diǎn)數(shù)的輸出格式,則格式標(biāo)志可以通過 ios:left | ios:dec |
26、ios:scientific 得到,16 進(jìn)制值為 0 x0812,10 進(jìn)制值為 2066。, 用成員函數(shù)對(duì)格式標(biāo)志進(jìn)行操作 置格式標(biāo)志 所謂設(shè)置格式標(biāo)志是將格式屬性 x_flags 的某 一位置1,使該位所對(duì)應(yīng)的格式標(biāo)志有效。設(shè) 置格式標(biāo)志的成員函數(shù)是 setf,調(diào)用該成員函 數(shù)的一般形式為: 流對(duì)象.setf (ios:格式標(biāo)志值); 例如: istream isobj; ostream osobj; isobj.setf(ios:skipws); osobj.setf(ios:left);,注意: isobj 和 osobj 為 istream 和 ostream 的用戶定 義對(duì)象。在
27、編程中使用最多的是通過系統(tǒng)預(yù) 定義流對(duì)象設(shè)置格式,例如: cin.setf(ios:skipws); cout.setf(ios:left); 所設(shè)置的格式標(biāo)志不改變格式屬性 x_flags 的 原有的有效位,即在原有基礎(chǔ)上追加設(shè)置。 例如,原來的狀態(tài)標(biāo)志字為: 0 x0011: 0000 0000 0001 0001 執(zhí)行 cout.setf(ios:left) 后, x_flags 的值變?yōu)椋?0 x0013: 0000 0000 0001 0011,例如: #include main() cout.setf(ios:showpos | ios:scientific); cout 567
28、567.89 endl; 程序執(zhí)行結(jié)果: +567 +5.6789e02, 清除格式標(biāo)志 與設(shè)置格式標(biāo)志操作相反,是將格式屬性 x_flags 的某一位清 0,使該位所對(duì)應(yīng)的格式特 性失效。清除格式的成員函數(shù)是 unsetf,調(diào)用 該成員函數(shù)的一般形式為: 流對(duì)象.unsetf(ios:格式標(biāo)志值); 注意:與設(shè)置格式標(biāo)志相似,所清除的格式標(biāo) 志只是使保存在 x_flags 中的當(dāng)前格式屬性的 相應(yīng)位失效,而不改變格式屬性其余的有效 位。例如,原格式屬性為:,0 x0013: 0000 0000 0001 0011 執(zhí)行 cout.unsetf(ios:left) 后,x_flags 的值變?yōu)?/p>
29、: 0 x0011: 0000 0000 0001 0001, 取狀態(tài)屬性 取出保存在 x_flags 中的格式屬性。完成這一 操作的成員函數(shù) flags,該函數(shù)有兩個(gè)重載版 本,調(diào)用它們的格式有兩種: long flags(); long flags(long flags); 前一種形式用于返回當(dāng)前格式屬性;后一種是 不僅將當(dāng)前格式屬性返回,并且將格式屬性設(shè) 置為指定值 flags。 注意,帶有參數(shù)的成員函數(shù) flags 與成員函數(shù) setf 不同,它對(duì)格式屬性的修改是覆蓋原值, 而不是在原值的基礎(chǔ)上追加設(shè)置。例如:,#include void showflags(long f)/ 顯示二進(jìn)
30、制形式的狀態(tài)字 long i; for (i = 0 x8000; i; i = i 1) if (i ,main() long f = cout.flags();showflags(f); cout.setf(ios:showpos | ios:scientific); f = cout.flags(); showflags(f); cout.unsetf(ios:scientific); f = cout.flags(); showflags(f); f = cout.flags(ios:oct);showflags(f); f = cout.flags(); showflags(f);
31、return 1; ,程序執(zhí)行結(jié)果: 0000000000000000 0000110000000000 0000010000000000 0000010000000000 0000000000100000 分析程序的執(zhí)行結(jié)果,可以清楚地看到格式屬 性值的變化情況。, 設(shè)置域?qū)?域?qū)捴饕脕砜刂埔粋€(gè)數(shù)據(jù)輸出時(shí)所占顯示區(qū) 域的寬度,在 ios 類中,域?qū)挻娣旁诒Wo(hù)類數(shù) 據(jù)成員 x_width 中。設(shè)置域?qū)挼某蓡T函數(shù)有兩 個(gè),調(diào)用它們的一般形式為: 流對(duì)象.width(); 流對(duì)象.width(域?qū)捴?; 第一種形式只用來返回當(dāng)前的域?qū)捴?,后者?來設(shè)置指定域?qū)?,并返回原來的域?qū)捴怠? 設(shè)置顯示的
32、精度 在 ios 類中,控制浮點(diǎn)數(shù)顯示精度位數(shù)是被保 存在保護(hù)類數(shù)據(jù)成員 x_precision 中的。設(shè)置顯 示精度的成員函數(shù)有兩個(gè),調(diào)用它們的一般形 式為: 流對(duì)象.precision(); 流對(duì)象.precision(精度位數(shù)); 第一種形式只用來返回當(dāng)前的顯示精度,后者 用來重新設(shè)置顯示精度,并返回原來的顯示精 度。, 設(shè)置填充字符 填充字符的作用是:當(dāng)輸出數(shù)據(jù)的長(zhǎng)度小于顯 示域?qū)挄r(shí),用填充字符來填充顯示域?qū)捴袛?shù)據(jù) 未占滿的空間。缺省情況下填充字符為空格。 如果輸出數(shù)據(jù)的長(zhǎng)度大于域?qū)挄r(shí),則填充字符 是沒有意義的。因此,在使用填充字符時(shí),必 須考慮與 width 函數(shù)相配合。在 ios
33、類中,填 充字符被保存在保護(hù)類數(shù)據(jù)成員 x_fill 中的。 設(shè)置填充字符的成員函數(shù)有兩個(gè),調(diào)用它們的 一般形式為:,流對(duì)象.fill(); 流對(duì)象.fill(填充字符); 第一種形式用來返回當(dāng)前的填充字符,后者用 來重新設(shè)置填充字符,并返回原有的填充字 符。例如:,#include main() cout x_width = cout.width() endl; cout x_fill = cout.fill() endl; cout x_precision = cout.precision() endl; cout 123 123.45678 endl; cout -n; cout * x
34、_width = 10, x_fill = , x_precision = 8 *n; cout.width(10); cout.precision(8); cout 123 123.45678 234.567 endl;,cout x_width = cout.width() endl; cout x_fill = cout.fill() endl; cout x_precision = cout.precision() endl; cout -n; cout * x_width = 10, x_fill = ,cout x_fill = cout.fill() endl; cout x_p
35、recision = cout.precision() endl; return 1; 程序執(zhí)行結(jié)果: x_width = 0 x_fill = x_precision = 6 123 123.457 -,* x_width = 10, x_fill = , x_precision = 8 * 123 123.45678 234.567 x_width = 0 x_fill = x_precision = 8 - * x_width = 10, x_fill = cout 123 setiosflags(ios:scientific) setw(20) 123.456789 endl; cou
36、t 123 setw(10) hex 123 endl; cout 123 setw(10) oct 123 endl; cout 123 setw(10) dec 123 endl; cout resetiosflags(ios:scientific) setprecision(4) 123.456789 endl; cout setiosflags(ios:left) setfill(#) setw(8) 123 endl;,cout resetiosflags(ios:left) setfill( 程序執(zhí)行結(jié)果: 123567 123 1.234568e+002 123 7b 7b 17
37、3 173 123 123.5 123# cin input i; cout i output i endl; return 1; 程序執(zhí)行結(jié)果: Enter number using hex format: a78e 42894 A78E返回,8.3 自定義類型的輸入輸出 從前面對(duì) C+ 流類庫的分析不難看出,系統(tǒng)預(yù)定義 類型數(shù)據(jù)的輸入輸出主要是通過使用輸入運(yùn)算符 (又稱為流的提取運(yùn)算符)和輸出運(yùn)算符 和輸出運(yùn)算符 是無法預(yù)先定義的。但卻 為用戶提供了使用運(yùn)算符重載為自定義類型對(duì)象定義 輸入輸出操作的面向?qū)ο蠓椒?。解決自定義類型對(duì)象 輸入輸出操作的思路和方法有三種:,1 用戶自定義類型總可以
38、分解成按指定結(jié)構(gòu)組織起來 的預(yù)定義類型,對(duì)這組預(yù)定義類型數(shù)據(jù)當(dāng)然可以使 用 或 運(yùn)算符。使用這種方法的缺點(diǎn): 在類外訪問被分解得到的預(yù)定義類型數(shù)據(jù)必須通 過接口,必然降低訪問效率。如果類數(shù)據(jù)成員均 定義為公有訪問屬性,雖然能提高訪問效率,但 破壞了面向?qū)ο蟮臄?shù)據(jù)隱藏原則。顯然不能兼顧 訪問效率和數(shù)據(jù)安全。 無法利用代碼的重用性,增加了程序冗余度; 程序的可讀性差;,2 在方法 1 的基礎(chǔ)上建立用戶自定義類的特定輸入輸 出成員函數(shù)。采用這種方法雖然解決了采用方法 1 的缺點(diǎn),但仍然存在以下缺點(diǎn): 增加了需要記憶的特定的輸入輸出成員函數(shù)名, 并在調(diào)用這些函數(shù)時(shí),需在函數(shù)名前加綴對(duì)象 名,因此增加了
39、編程的復(fù)雜性。 這些函數(shù)只能單獨(dú)使用(寫成一個(gè)單獨(dú)語句), 而不能放在輸入或輸出連續(xù)表達(dá)式中,無法統(tǒng)一 輸入輸出操作的形式。 3 采用重載 和 運(yùn)算符的方法,并將運(yùn)算符 函數(shù)定義成被輸入或輸出對(duì)象類的友元函數(shù)。這種 方法將會(huì)消除前兩種方法所帶來的缺點(diǎn),是一種遵 循面向?qū)ο笤O(shè)計(jì)原則的方法。,8.3.1 重載輸入運(yùn)算符 輸入運(yùn)算符 是輸入流類(將在第八章中詳細(xì)講 述)的成員函數(shù)。該運(yùn)算符也是一個(gè)雙目運(yùn)算符,它 的左操作數(shù)必須是輸入流類對(duì)象的引用,表示被輸入 的信息必須來自標(biāo)準(zhǔn)的輸入流設(shè)備;而右操作數(shù)是接 收輸入信息的指定類對(duì)象的引用。因此,為自定義類 重載的輸入運(yùn)算符函數(shù)只能是類成員函數(shù)。,1 原
40、型 friend 輸入流類,2 定義 輸入流 ,3 調(diào)用 cin 類對(duì)象名; 例如: point pt; cin pt;,注意: 輸入運(yùn)算符重載函數(shù)的第一個(gè)參數(shù)的類型必須是輸 入流類 istream 對(duì)象的引用,形參名(流對(duì)象名)可 以使用任何合法的標(biāo)識(shí)符。 輸入運(yùn)算符重載函數(shù)的第二個(gè)參數(shù)的類型必須是接 收輸入信息的指定類對(duì)象的引用,例如 point cout pt;,注意: 輸出運(yùn)算符重載函數(shù)的第一個(gè)參數(shù)的類型必須是輸 出流類 ostream 對(duì)象的引用,形參名(流對(duì)象名)可 以使用任何合法的標(biāo)識(shí)符。 輸出運(yùn)算符重載函數(shù)的第二個(gè)參數(shù)的類型必須是輸 出信息的指定類對(duì)象或?qū)ο蟮囊茫?poi
41、nt/ 輸入流對(duì)象 ofstream out;/ 輸出流對(duì)象 fstream io;/ 輸入輸出流對(duì)象,使用文件流類的成員函數(shù) open 打開文件,也就是 使某一個(gè)文件與指定流相關(guān)聯(lián)。open 的原型: void open( const char* szName, int mode, int nProt = filebuf:openprot ); 其中三個(gè)參數(shù)分別為: 1 文件名:字符串常量 szName 用來傳遞文件名。 2 打開方式:整型值 mode 指定了文件被打開的方 式,其取值范圍如下表所示:,在 ios 類定義中 mode 值被定義為以下枚舉: enum open_mode in
42、= 0 x01, out = 0 x02, ate = 0 x04, app = 0 x08, trunc = 0 x10, nocreate = 0 x20, noreplace = 0 x40, binary = 0 x80 ;,各個(gè)枚舉值所指定的打開方式的詳細(xì)含義: 追加方式 ios:app: The function performs a seek to the end of file. When new bytes are written to the file, they are always appended to the end, even if the position is
43、 moved with the ostream:seekp function. 查詢文件尾方式 ios:ate: The function performs a seek to the end of file. When the first new byte is written to the file, it is appended to the end, but when subsequent bytes are written, they are written to the current position., 輸入方式 ios:in: The file is opened for i
44、nput. The original file(if it exists) will not be truncated. 輸出方式 ios:out: The file is opened for output. 更新方式 ios:trunc: If the file already exists, its contents are discarded. This mode is implied if ios:out is specified, and ios:ate, ios:app, and ios:in are not specified., 禁創(chuàng)建方式 ios:nocreate:VC+
45、2005 無此方式 If the file does not already exist, the function fails. 禁替換方式 ios:noreplace:VC+ 2005 無此方式 If the file already exists, the function fails. 二進(jìn)制方式 ios:binary: Opens the file in binary mode (the default is text mode). Note that there is no ios:in or ios:out default mode for fstream objects. Yo
46、u must specify both modes if your fstream object must both read and write files.,3 訪問保護(hù)方式:整數(shù)值 nProt 指定了被打開文件的 訪問保護(hù)方式(文件的訪問類型)。從函數(shù)原型 中可以知道 nProt 的缺省值是 filebuf:openprot,該 值對(duì)于 UNIX 操作系統(tǒng)是 0 x644,即普通文件。在 DOS 或 Windows 操作系統(tǒng)中, nProt 的值通常對(duì) 應(yīng)文件屬性,它們是: 0普通文件 1只讀文件 2隱含文件 4系統(tǒng)文件 8備份文件,4 調(diào)用實(shí)例 打開一個(gè)輸出文件 ofstream ou
47、t; out.open(test, ios:out, 0); 按普通文件訪問打開一個(gè)輸出文件 “test”,與輸 出文件流 out 相關(guān)聯(lián)。由于普通文件訪問方式 和輸出方式都是輸出文件流的缺省創(chuàng)建方式, 因此,調(diào)用 open 函數(shù)的形式可簡(jiǎn)化為: out.open(test);, 打開一個(gè)輸入輸出文件 fstream both; both.open(test, ios:in | ios:out, 0); 由于文件流都提供具有打開文件功能的構(gòu)造函數(shù) (文件名、打開和訪問方式均可作為參數(shù)),所 以創(chuàng)建文件流對(duì)象和打開文件用可以一步完成: ofstream out(test); fstream bo
48、th(test, ios:in | ios:out, 0); 注意,文件打開操作是否成功應(yīng)調(diào)用成員函數(shù) fail 進(jìn)行檢查,避免對(duì)無效文件讀寫所引起的系統(tǒng)錯(cuò)誤。,fstream both; both.open(test, ios:in | ios:out, 0); if (both.fail() cout Cannot open file! n; 錯(cuò)誤處理語句 文件使用完畢后,應(yīng)該關(guān)閉文件,并與所關(guān)聯(lián)的文 件流 “分離”。關(guān)閉文件使用文件流的成員函數(shù) close()。 例如: both.close();,8.4.2 文件的讀寫 1 文本文件的讀寫 一旦文件被成功打開,文件中的文本數(shù)據(jù)信息的讀
49、寫操作與控制臺(tái)文件信息的輸入輸出操作是完全一 致的。從流類庫的定義說明中我們知道可以用于文 本數(shù)據(jù)輸入和輸出的運(yùn)算符 和 是分別在 輸入流類 istream 和輸出流類 ostream 中定義的,而 用于文件讀寫的流類 ifstream、ofstream 和 fstream 是 istream 和 ostream 的派生類,它們之間的層次關(guān)系 如下:,顯然, 和 也是 ifstream,ofstream 和 fstream 的運(yùn)算符,但調(diào)用時(shí),必須用 ifstream,ofstream 或 fstream 流類對(duì)象替代控制臺(tái)文本信息輸入輸出使用 的輸入流類對(duì)象(例如,cin)和輸出流類對(duì)象(例
50、 如,cout )。,istream,ostream,fstreambase,例8-5 把一個(gè)整數(shù)、一個(gè)浮點(diǎn)數(shù)和一個(gè)字符串以文本 形式寫入一個(gè)磁盤文件 test 中。顯然,該程序執(zhí) 行后,屏幕上是不會(huì)顯示任何與程序有關(guān)的信息 的。而程序產(chǎn)生的磁盤文件可以使用 DOS 系統(tǒng) 的 type 命令或使用 Windows 平臺(tái)的 “記事本” 或 其他可以讀寫純文本文件的工具查看。文件“test” 中記錄的信息為: 10 123.456 This is a text file.,例8-6 先建立一個(gè)輸出文件 “test2”,向它寫入數(shù)據(jù), 然后關(guān)閉文件,再按輸入模式打開 “test2” ,并 讀取和顯示
51、文件中的信息。 語句 fout 100 hex 100 endl; 使第二 個(gè)10進(jìn)制 100 轉(zhuǎn)換為16進(jìn)制表示的文本串寫入文 件 test2。使用 debug 程序可以看到文件中兩個(gè)數(shù) 據(jù)文本存儲(chǔ)格式: 48 65 6C 6C 6F 21 20 0D-0A 31 30 30 20 36 34 0D Hello!.100 64. 0A ., 按程序中的語句 fin str i j; 讀入數(shù)據(jù)后,j 中保存的不是10 進(jìn)制 100,而是10 進(jìn)制 64。如 果要使 j = 100,則需要將上述語句改為: fin str i hex j; 此時(shí),程序執(zhí)行結(jié)果為: Hello! 100 100,例
52、8-7 從鍵盤讀入字符串、并將它們寫入磁盤。當(dāng)用 戶輸入空白字符時(shí),程序停止。 問題分析: 本程序采用了命令行參數(shù)的形式,執(zhí)行程序時(shí), 命令行中除程序的執(zhí)行文件名外,還需要傳遞一 個(gè)參數(shù),即輸出文件名。因此命令行參數(shù)計(jì)數(shù) argc = 2, 執(zhí)行文件名保存在 argv0 中,而輸出文 件名被存放在 argv1 中。例如,輸出文件名為 file,則命令行應(yīng)該是:write file 程序執(zhí)行時(shí),首先在屏幕上顯示用戶輸入提示。 用戶從鍵盤輸入字符串,并寫入命令行指定的輸 出文件中,直至輸入 CTRL-Z,即 ASCII 碼 0 輸入停止,文件關(guān)閉,程序執(zhí)行結(jié)束。,2 二進(jìn)制文件的讀寫 任何文件中無
53、論包含是文本數(shù)據(jù)還是二進(jìn)制數(shù)據(jù), 都能以文本方式或二進(jìn)制方式打開。這就是說,文 件的打開方式并不能保證文件數(shù)據(jù)的形式和含義, 而確保文件數(shù)據(jù)的形式和含義關(guān)鍵是如何對(duì)文件的 數(shù)據(jù)進(jìn)行讀寫。二進(jìn)制文件中的數(shù)據(jù)是直接將數(shù)據(jù) 在內(nèi)存中存放的形式映像到文件中,因此在讀寫過 程中不能發(fā)生任何轉(zhuǎn)換。顯然,這樣的讀寫操作是 不能使用輸入運(yùn)算符 “” 和輸出運(yùn)算符 “” 完成 的。對(duì)二進(jìn)制文件的讀寫操作有兩種: 使用 get 函數(shù)和 put 函數(shù)讀寫單字節(jié); 使用 read 函數(shù)和 write 函數(shù)讀寫指定長(zhǎng)度的字節(jié)。, 使用 get 函數(shù)和 put 函數(shù)讀寫二進(jìn)制文件 get 是 istream 類的成員函數(shù)
54、。函數(shù)原型: inline istream,功能:從輸入流對(duì)象關(guān)聯(lián)的文件中讀數(shù)據(jù), 每次讀1字節(jié),讀指針自動(dòng)增1。 put 是 ostream 類的成員函數(shù)。函數(shù)原型 inline ostream 功能:向輸出流對(duì)象關(guān)聯(lián)的文件中寫數(shù)據(jù), 每次寫1字節(jié),寫指針自動(dòng)增1。,例8-8一個(gè)實(shí)現(xiàn)任意文件復(fù)制的簡(jiǎn)單程序。 問題分析: 與例8-7相同也采用了命令行參數(shù)的形式,所 不同的是在執(zhí)行程序時(shí),命令行中應(yīng)包含執(zhí)行 文件名,源文件名和目標(biāo)文件名。因此命令行 參數(shù)計(jì)數(shù) argc = 3,執(zhí)行文件名保存在 argv0 中,源文件名存放在 argv1 中,目標(biāo)文件名 存放在 argv2 中。若執(zhí)行文件名為 d
55、uplicate, 源文件名為 file,目標(biāo)文件名為 file1,則執(zhí)行 時(shí)的命令行應(yīng)該是:duplicate file file1 如果命令行的參數(shù)個(gè)數(shù)不等于3,則顯示命令 行格式提示并退出執(zhí)行。, 二進(jìn)制文件的處理過程與文本文件的處理過 程基本相同,但判斷文件結(jié)束時(shí)有所區(qū)別: 文本文件:遇到文件結(jié)束符,get 函數(shù)返回文 件結(jié)束標(biāo)志EOF,該標(biāo)志值為 -1,它有別 于其它任何文本字符。 二進(jìn)制文件:由于 -1 也是有效二進(jìn)制數(shù)據(jù), 所以不能使用 EOF 作為判斷文件結(jié)束的標(biāo) 志。為解決這個(gè)問題,應(yīng)使用另一個(gè)成員 函數(shù) eof,用來判斷文件結(jié)束,其原型為: int eof(); 當(dāng)?shù)竭_(dá)文件
56、尾時(shí),它返回 bool 值 true,否 則返回 false。,例8-9實(shí)現(xiàn)在屏幕上顯示任何文件的內(nèi)容。 注意:指定文件打開方式為 ios:binary 并不是按 二進(jìn)制讀寫文件數(shù)據(jù)的必要條件。如果不存在對(duì) 二進(jìn)制文件的特定判別問題,就不一定需要使用 ios:binary 方式打開文件。在例8-8和例8-9中,都 沒有指定文件打開方式為 ios:binary。, 使用 read 函數(shù)和 write 函數(shù)讀寫二進(jìn)制文件 read 是 istream 類的成員函數(shù)。函數(shù)原型: istream 功能:從相應(yīng)的流中讀取 num 個(gè)字節(jié),并將 它們存放到指針 buf 所指的緩沖區(qū)中, 讀指針自動(dòng)增加 n
57、um 。 在調(diào)用該函數(shù)時(shí),需要傳遞兩個(gè)參數(shù):緩沖 區(qū)的首地址和從文件中讀取的字節(jié)數(shù),,其調(diào)用格式如下: read(緩沖區(qū)首址, 讀入的字節(jié)數(shù)); 注意:“緩沖區(qū)”的數(shù)據(jù)類型為 unsigned char, 如果讀取的數(shù)據(jù)為其他類型時(shí),則須進(jìn)行類 型轉(zhuǎn)換,例如: int array = 50, 60, 70; read(usigned char*), write 是 ostream 類的成員函數(shù)。函數(shù)原型: ostream 功能:從 buf 所指向的緩沖區(qū)中將 num 個(gè)字節(jié) 寫到相應(yīng)的文件中。寫指針自動(dòng)增加 num。 在調(diào)用該函數(shù)時(shí),所需參數(shù)與 read 類似。,例8-10 用 write 函數(shù)向文件 “test” 中寫入雙精度數(shù) 與字符串。 顯然,該程序執(zhí)行后,屏幕上將不會(huì)顯示任何信 息,而且不能使用 DOS 系統(tǒng)的 type 命令或使用 Windows 平臺(tái)的 “記事本” 或其他可以讀寫純
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 電機(jī)與電氣控制技術(shù) 課件 任務(wù)7.1.1交流異步電機(jī)的調(diào)速控制
- 某著名企業(yè)高層管理人員薪酬調(diào)查報(bào)告0729
- 人血白蛋白臨床使用規(guī)范總結(jié)2026
- 《GBT 9734-2008化學(xué)試劑 鋁測(cè)定通 用方法》專題研究報(bào)告
- 《GBT 5009.49-2008發(fā)酵酒及其配制酒衛(wèi)生標(biāo)準(zhǔn)的分析方法》專題研究報(bào)告
- 《GBT 22402-2008攝影 加工用化學(xué)品 無水硫代硫酸鈉和五水合硫代硫酸鈉》專題研究報(bào)告長(zhǎng)文
- 《FZT 52048-2017有機(jī)阻燃粘膠短纖維》專題研究報(bào)告
- 道路安全教育培訓(xùn)班課件
- 道路交通類法律培訓(xùn)課件
- 2026年高校時(shí)政熱點(diǎn)試題含解析及答案
- 眼鏡驗(yàn)光師試題(及答案)
- 選人用人方面存在的問題及改進(jìn)措施
- 項(xiàng)目管理流程標(biāo)準(zhǔn)作業(yè)程序手冊(cè)
- 自我介紹禮儀課件
- 衛(wèi)生院孕優(yōu)知識(shí)培訓(xùn)課件
- 2025-2030工業(yè)窯爐煙氣多污染物協(xié)同控制技術(shù)
- 培訓(xùn)機(jī)構(gòu)臺(tái)賬
- 電商預(yù)算表格財(cái)務(wù)模板全年計(jì)劃表格-做賬實(shí)操
- 泵車日常管理辦法
- 骨科術(shù)后疼痛評(píng)估與護(hù)理查房
- 輸液泵的使用培訓(xùn)課件
評(píng)論
0/150
提交評(píng)論