




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領
文檔簡介
1、第八章 C+ 的 I/O 流庫,C+ 為什麼要建立自己的輸入輸出系統(tǒng)? 1 C 雖然具有一個靈活和功能強大的輸入輸出系統(tǒng), 但它并不支持自定義類型。例如: class account char name30; double balance; public: account(); account(char*, double); ;, account acnt; scanf(“%account”, / 錯誤,不支持 account 類型 因為輸入函數(shù) scanf 和輸出函數(shù) printf 的格式串形參 只能與系統(tǒng)預定義類型匹配,而無法識別用戶的自 定義類型,并且也不能通過重載定義 scanf 和
2、printf 函數(shù)的新版本,使它們的格式串形參能匹配任意用 戶自定義類型。,2 面向?qū)ο蟪绦蛟O計必須定義眾多的用戶自定義類, 如何以面向?qū)ο蟮脑O計原則和方法為自定義類設計 既規(guī)格統(tǒng)一,又適應個性化的輸入輸出操作行為是 十分必要的。因此 C+ 必須建立一個能通過對輸入 輸出操作重載的方法實現(xiàn)對任意自定義類型對象輸 入輸出支持的系統(tǒng)。,本章要點 1 C+ 流庫結(jié)構(gòu) 流庫的概念、流庫的組成。 2 標準輸入輸出流 輸入輸出流類的定義、輸入輸出運算符、輸入輸出 的格式控制。 3 自定義類的輸入輸出 輸入輸出運算符的重載。 4 文件的輸入輸出流 文件的打開、關閉和讀寫。 5使用 MFC 的對話框類實現(xiàn)輸入
3、輸出,8.1 C+ 流庫結(jié)構(gòu) 8.1.1 流庫的概念 流(stream)是從源(數(shù)據(jù)的生產(chǎn)者)到目標(數(shù) 據(jù)的使用者)被傳輸數(shù)據(jù)的引用。每個流都是一個與 某種數(shù)據(jù)傳輸設備相關聯(lián)的對象。 流具有方向性: 輸入流是與輸入設備(如鍵盤)關聯(lián)的流。 輸出流是與輸出設備(如顯示器屏幕)關聯(lián)的流。 輸入輸出流是與輸入輸出設備(如磁盤)關聯(lián)的流。,C+ 中包含的預定義流: cin 輸入流,與輸入設備關聯(lián)。 cout 輸出流,與輸出設備關聯(lián)。 cerr 非緩沖型錯誤信息流,與錯誤輸出設備關聯(lián); clog 緩沖型錯誤信息流,與錯誤輸出設備關聯(lián)。 在缺省情況下,指定的輸入設備是控制臺鍵盤,輸 出設備是控制臺顯示器
4、終端。在任何情況下,指定的 錯誤輸出設備總是控制臺顯示器終端。,cin 和 cout 的使用方法我們已經(jīng)很熟悉了。cerr 和 clog 均是用來輸出錯誤信息,它們的使用方法與 cout 基本相同,只不過它們所關聯(lián)的設備始終是控制臺顯 示器,而不隨著 cout 關聯(lián)設備的改變而變化。cerr 和 clog 之間的區(qū)別是: cerr 對輸出的錯誤信息不緩沖,因而發(fā)送給它的任何內(nèi) 容都立即輸出。 clog 輸出的錯誤信息被緩沖,當緩沖區(qū)滿時才進行輸 出,也可以通過刷新流的方式(遇到操縱符 endl 或 flush)強迫刷新緩沖區(qū)導致顯示輸出。,下面給出一段使用預定義輸入輸出流信息的程序: 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計方法建立起來的輸入 輸出類庫,它具有兩個平行的根基類 streambuf 和 ios, 庫中所有其他的類均從它們直接或間接派生。系統(tǒng)中 預定義流,cin、cout、cerr、clog 都是流庫中相應類的 對象。,8.1.2 streambuf
6、類 streambuf 類是流庫的根基類,它為輸入輸出物理設 備提供緩沖區(qū)和流處理的一些通用方法。 C+ 將輸入輸出流均視為字節(jié)流,因此緩沖區(qū)是由 一個字符串和兩個指針組成的。這兩個指針分別指 向數(shù)據(jù)流在輸入緩沖區(qū)中的插入位置和在輸出緩沖 區(qū)的提取位置。 streambuf 類提供對緩沖區(qū)的底層操作,例如設置緩 沖區(qū)、對緩沖區(qū)指針進行操作、從緩沖區(qū)取字節(jié)、向 緩沖區(qū)存儲字節(jié)等。streambuf 類有三個派生類,filebuf 類、strstreambuf 類和 conbuf 類。它們的派生層次關系 如圖所示:, filebuf 類擴展了 streambuf 類的功能,用于文件流與 文件緩沖區(qū)
7、相關聯(lián),實現(xiàn)對文件緩沖區(qū)中的字節(jié)序 列的讀寫操作: 寫文件:緩沖區(qū)內(nèi)容按字節(jié)寫到指定的文件中, 然后刷新緩沖區(qū)。 讀文件:指定文件內(nèi)容按字節(jié)讀到緩沖區(qū)中。 打開文件:filebuf 與被讀或?qū)懙奈募嚓P聯(lián)。,streambuf, 關閉文件:filebuf 與被讀或?qū)懙奈募獬P聯(lián)。 strstreambuf 類擴展了 streambuf 類的功能,提供了將 內(nèi)存作為輸入輸出設備時,進行提取和插入操作的 緩沖區(qū)管理。 conbuf 類擴展了 streambuf 類的功能,用于控制臺顯 示器輸出緩沖區(qū)關聯(lián)和管理,提供光標控制、顏色 設置、活動窗口定義、清屏、行清除等屏幕控制功 能(注意,這些屏幕控
8、制功能在有些編譯器版本中 不提供,例如 visual C+)。 通常情況下,對設備緩沖區(qū)的操作一般使用上述三 個派生類,很少直接使用基類 streambuf。,8.1.3 ios 類 ios 類及其派生類為用戶提供使用流的接口,該類具 有一個 streambuf 類型指針指向流的緩沖區(qū)。ios 類及其 派生類對象通過該指針使用 streambuf 及其派生類對象 完成輸入輸出時的格式化或非格式化轉(zhuǎn)換,并檢查輸 入輸出的錯誤。ios 是流庫中的另一個根基類,它有四 個直接派生類: 輸入流類 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; 這四個派生類成為流類庫中的基本流類,它們又組 合派生出以下的流類: 輸入文件流類 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; 控制臺輸出流類 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 又分別派生出 具有賦值運算符“=”重載的新類: 帶賦值的輸入流類 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)預定義流 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 等流類定義 自己的流對象,例如:istream is;ostream os; 對預定義類型數(shù)據(jù)的輸入輸出操作已經(jīng)定義為流類 的操作,而對用戶自定義類型對象的輸入輸出操作則 可以通過重載運算符 “”和“” 得以實現(xiàn)。,Java 的 I/O 流類在構(gòu)造和使用上與 C+ 有一些有趣 的差別: 1 C+ 的 I/O 流類庫是把所有的輸入輸出功能封裝在 數(shù)量相對較少的幾個流類中,自定義類則是通過重 載機制使得
14、流類對象能夠?qū)ψ远x類對象進行輸入 輸出操作。 而 Java 則幾乎為每一種情況提供了一個獨立的類。 例如,底層的字節(jié)流操作類、按數(shù)據(jù)類型劃分的各 種高級操作類,對底層 I/O 包裝后進行某種特定操 作(如 Unicode 讀寫)的類,隨機讀寫操作類,數(shù) 組讀寫類等等。,2 C+ 的流在缺省情況下是進行緩沖的,但 Java 的流 在缺省情況下是不緩沖的。但可以調(diào)用提供了緩沖 功能的類對一個 Java 的流進行緩沖。 3 在 Java 中,所有的整數(shù)和浮點數(shù)都是以大端字節(jié)順 序進行輸入輸出的,與底層平臺無關。這與 C+ 中 的情況不同,因此 Java 所產(chǎn)生的數(shù)據(jù)文件的可移植 性更高。,4 在典
15、型的 C+ 程序中,字符均使用 ASCII 編碼形式 表示(無論是單獨使用的字符還是字符串中的字 符)。這與字符從輸入設備讀入或?qū)懙捷敵鲈O備都 保持 ASCII 編碼形式是一致的。 一個典型的 Java 程序中,字符始終是用兩個字節(jié)的 Unicode 形式表示的。當從輸入設備讀入 ASCII 編碼 形式的字符時,必須先轉(zhuǎn)換為 Unicode 形式后再寫 入內(nèi)存;當將 Unicode 形式字符寫到輸出設備時, 必須先轉(zhuǎn)換為 ASCII 編碼形式后再寫入輸出設備。 Java 的流類的層次結(jié)構(gòu)如下圖所示:,OutputStream,InputStream,返回,Writer,Reader,8.2 標
16、準輸入輸出流 8.2.1 輸入輸出流類定義 istream 類和 ostream 類在流庫中分別提供基本的標 準輸入輸出操作,是使用流庫的主要接口,在系統(tǒng)頭 文件 iostream.h 中,它們的類定義分別如下: class istream:virtual public ios public: istream(streambuf*);/構(gòu)造函數(shù) / 從輸入流中將字符讀取到給定指針 char* 指向的內(nèi)存,直 / 至遇到分界符、文件結(jié)束符或讀至(len-1)個字符為止。 istream,/ 從輸入流讀取字符到給定的 streambuf,直至遇到分界符。 istream,/ 從讀入流讀取給定數(shù)目的
17、字符到 char* 指向的內(nèi)存空間。 / 如果發(fā)生錯誤時,getcount 函數(shù)可得到實際讀入的數(shù)目。 istream,/ 按給定偏移 streamoff ( typedef long streamoff)移動輸入 / 文件指針,指示偏移方向的枚舉值 ios:seek_dir 的取值: / beg = 從文件開始;cur = 從當前位置;end = 從文件尾。 istream /對系統(tǒng)所有的預定義類型都給出了的重載定義。 ;,class ostream:virtual public ios public: ostream(streambuf*);/ 構(gòu)造函數(shù) ostream,streampos
18、 tellp(); / 返回輸出流中當前指針位置。 / 可重載的輸出運算符 ostream,8.2.2 輸入輸出運算符的使用 8.2.3 格式控制的輸入輸出 輸入輸出的格式控制可以使得人機交互界面更加友 好、美觀。在 C 程序中,輸入輸出是使用 C 運行庫的 scanf 和 printf 函數(shù)完成的,輸入輸出的格式是通過這兩 個函數(shù)的格式描述串參數(shù)控制的。在 C+ 程序中,雖 仍然可以使用 scanf 和 printf 函數(shù),但在面向?qū)ο蟮某?序設計中,輸入輸出是使用流類庫中的輸入輸出流完 成的,因此輸入輸出的格式控制必須使用流類庫提供 的格式控制的方法: 使用 ios 類的格式控制成員函數(shù);
19、 使用被稱為格式操縱符的特殊函數(shù)。,1 用 ios 類成員函數(shù)進行輸入輸出格式化 ios 類提供了用于輸入輸出格式控制的成員函數(shù)。 這些函數(shù)進行格式控制的方法是修改以下屬性: 格式標志屬性 x_flags:標志的不同狀態(tài)值指定輸 入輸出數(shù)據(jù)的不同格式(如對齊規(guī)則、數(shù)值轉(zhuǎn)換 基、數(shù)字表示規(guī)則等)。 輸出域?qū)拰傩?x_width: 指定輸出數(shù)據(jù)所占顯示 區(qū)域的寬度。 填充字符屬性 x_fill:指定輸出顯示域中數(shù)據(jù)為占 空間的填充字符; 輸出精度屬性 x_precision:指定浮點數(shù)輸出的小 數(shù)部分顯示位數(shù)。, 格式標志 C+ 中每個流對象的輸入輸出格式都是依據(jù)指定 格式進行的,也就是說,流對象
20、的每次輸入“” 操作是按照當前格式標志 x_flags 中 的格式狀態(tài)完成的。該屬性是一個 protected 成 員,在類外訪問該屬性是通過公有的格式控制成 員函數(shù)實現(xiàn)的。注意,該屬性可以在 ios 的派生 類內(nèi)被訪問。為了便于提供格式控制成員函數(shù)的 參數(shù)和參數(shù)具有良好的可讀性,ios 類定義了一 個公有的無名枚舉數(shù)據(jù)成員,用戶可以使用這些 特定的枚舉元素,形成所需要的格式狀態(tài)傳遞給 相應的格式控制成員函數(shù)。,class _CRTIMP ios public: enum skipws = 0 x0001, / 跳過輸入中的空白,用于輸入 left = 0 x0002, / 左對齊輸出,用于輸
21、出 right = 0 x0004, / 右對齊輸出,用于輸出 internal = 0 x0008, / 符號或基數(shù)指示符與數(shù)字之間添加填充符,用于輸出 dec = 0 x0010, / 基數(shù)為 10 進制,用于輸入輸出 oct = 0 x0020, / 基數(shù)為 8 進制,用于輸入輸出 hex = 0 x0040, / 基數(shù)為 16 進制,用于輸入輸出,showbase = 0 x0080, / 顯示基數(shù)指示符,用于輸出 showpoint = 0 x0100, / 顯示小數(shù)點,用于輸出 uppercase = 0 x0200, / 16 進制輸出時,數(shù)基指示符和 / 數(shù)值中的字母一律為大寫
22、,用于輸出 showpos = 0 x0400, / 正數(shù)前顯示+符號,用于輸出 scientific = 0 x0800, / 科學表示法浮點數(shù),用于輸出 fixed = 0 x1000, / 定點形式顯示浮點數(shù),用于輸出 unitbuf = 0 x2000, /輸出后立即刷新流,用于輸出。 stdio = 0 x4000, / 刷新 stdout 和 stderr,用于輸出。 ; inline long flags() const;/ 返回當前格式標志。,inline long flags(long _l); / 設置指定格式 _l,返回原有格式。 inline long setf(lon
23、g _f, long _m); / 依據(jù)掩碼 _m 設置指定格式 _f,返回原有格式。inline long unsetf(long _l); / 清除指定格式 _l,并返回原有標志。 inline int width() const;/ 返回當前域?qū)捴怠?inline int width(int _i); / 設置指定域?qū)?_i,并返回原有域?qū)捴怠?inline ostream* tie(ostream* _os); / 將流連接到_os 指向輸出流,并返回原來的流指針。 inline ostream* tie() const;/ 返回原來的流指針。,inline fill() const;
24、/ 返回當前填充字符。 inline char fill(char _c); / 設置指定填充字符,并返回原有填充字符。 inline int precision(int _i); / 設置指定浮點數(shù)精度,并返回原有浮點數(shù)精度。 inline int precision() const;/ 返回當前的浮點數(shù)精度。 inline int rdstate() const;/ 返回當前的錯誤狀態(tài)。 inline void clear(int _i = 0); / 根據(jù)掩碼 _i 設置或清除錯誤狀態(tài)位。 protected: ,long x_flags; int x_precision; char x
25、_fill; int x_width; ;,格式枚舉元素值有一個共同的特點,即使用不同 位為 1 二進制數(shù)表示不同的格式值,也就是說, 枚舉元素值的二進制表示只有一位為 1。例如: skipws0 x0001: 0000 0000 0000 0001 left0 x0002: 0000 0000 0000 0010 right0 x0004: 0000 0000 0000 0100 顯然,所需要的特定格式標志將可以是一個枚舉 元素值或幾個的枚舉元素進行或運算組合而成, 例如,欲設置左對齊 10 進制科學表示法顯示浮 點數(shù)的輸出格式,則格式標志可以通過 ios:left | ios:dec |
26、ios:scientific 得到,16 進制值為 0 x0812,10 進制值為 2066。, 用成員函數(shù)對格式標志進行操作 置格式標志 所謂設置格式標志是將格式屬性 x_flags 的某 一位置1,使該位所對應的格式標志有效。設 置格式標志的成員函數(shù)是 setf,調(diào)用該成員函 數(shù)的一般形式為: 流對象.setf (ios:格式標志值); 例如: istream isobj; ostream osobj; isobj.setf(ios:skipws); osobj.setf(ios:left);,注意: isobj 和 osobj 為 istream 和 ostream 的用戶定 義對象。在
27、編程中使用最多的是通過系統(tǒng)預 定義流對象設置格式,例如: cin.setf(ios:skipws); cout.setf(ios:left); 所設置的格式標志不改變格式屬性 x_flags 的 原有的有效位,即在原有基礎上追加設置。 例如,原來的狀態(tài)標志字為: 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, 清除格式標志 與設置格式標志操作相反,是將格式屬性 x_flags 的某一位清 0,使該位所對應的格式特 性失效。清除格式的成員函數(shù)是 unsetf,調(diào)用 該成員函數(shù)的一般形式為: 流對象.unsetf(ios:格式標志值); 注意:與設置格式標志相似,所清除的格式標 志只是使保存在 x_flags 中的當前格式屬性的 相應位失效,而不改變格式屬性其余的有效 位。例如,原格式屬性為:,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ù)有兩個重載版 本,調(diào)用它們的格式有兩種: long flags(); long flags(long flags); 前一種形式用于返回當前格式屬性;后一種是 不僅將當前格式屬性返回,并且將格式屬性設 置為指定值 flags。 注意,帶有參數(shù)的成員函數(shù) flags 與成員函數(shù) setf 不同,它對格式屬性的修改是覆蓋原值, 而不是在原值的基礎上追加設置。例如:,#include void showflags(long f)/ 顯示二進
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é)果,可以清楚地看到格式屬 性值的變化情況。, 設置域?qū)?域?qū)捴饕脕砜刂埔粋€數(shù)據(jù)輸出時所占顯示區(qū) 域的寬度,在 ios 類中,域?qū)挻娣旁诒Wo類數(shù) 據(jù)成員 x_width 中。設置域?qū)挼某蓡T函數(shù)有兩 個,調(diào)用它們的一般形式為: 流對象.width(); 流對象.width(域?qū)捴?; 第一種形式只用來返回當前的域?qū)捴?,后者?來設置指定域?qū)?,并返回原來的域?qū)捴怠? 設置顯示的
32、精度 在 ios 類中,控制浮點數(shù)顯示精度位數(shù)是被保 存在保護類數(shù)據(jù)成員 x_precision 中的。設置顯 示精度的成員函數(shù)有兩個,調(diào)用它們的一般形 式為: 流對象.precision(); 流對象.precision(精度位數(shù)); 第一種形式只用來返回當前的顯示精度,后者 用來重新設置顯示精度,并返回原來的顯示精 度。, 設置填充字符 填充字符的作用是:當輸出數(shù)據(jù)的長度小于顯 示域?qū)挄r,用填充字符來填充顯示域?qū)捴袛?shù)據(jù) 未占滿的空間。缺省情況下填充字符為空格。 如果輸出數(shù)據(jù)的長度大于域?qū)挄r,則填充字符 是沒有意義的。因此,在使用填充字符時,必 須考慮與 width 函數(shù)相配合。在 ios
33、類中,填 充字符被保存在保護類數(shù)據(jù)成員 x_fill 中的。 設置填充字符的成員函數(shù)有兩個,調(diào)用它們的 一般形式為:,流對象.fill(); 流對象.fill(填充字符); 第一種形式用來返回當前的填充字符,后者用 來重新設置填充字符,并返回原有的填充字 符。例如:,#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 自定義類型的輸入輸出 從前面對 C+ 流類庫的分析不難看出,系統(tǒng)預定義 類型數(shù)據(jù)的輸入輸出主要是通過使用輸入運算符 (又稱為流的提取運算符)和輸出運算符 和輸出運算符 是無法預先定義的。但卻 為用戶提供了使用運算符重載為自定義類型對象定義 輸入輸出操作的面向?qū)ο蠓椒?。解決自定義類型對象 輸入輸出操作的思路和方法有三種:,1 用戶自定義類型總可以
38、分解成按指定結(jié)構(gòu)組織起來 的預定義類型,對這組預定義類型數(shù)據(jù)當然可以使 用 或 運算符。使用這種方法的缺點: 在類外訪問被分解得到的預定義類型數(shù)據(jù)必須通 過接口,必然降低訪問效率。如果類數(shù)據(jù)成員均 定義為公有訪問屬性,雖然能提高訪問效率,但 破壞了面向?qū)ο蟮臄?shù)據(jù)隱藏原則。顯然不能兼顧 訪問效率和數(shù)據(jù)安全。 無法利用代碼的重用性,增加了程序冗余度; 程序的可讀性差;,2 在方法 1 的基礎上建立用戶自定義類的特定輸入輸 出成員函數(shù)。采用這種方法雖然解決了采用方法 1 的缺點,但仍然存在以下缺點: 增加了需要記憶的特定的輸入輸出成員函數(shù)名, 并在調(diào)用這些函數(shù)時,需在函數(shù)名前加綴對象 名,因此增加了
39、編程的復雜性。 這些函數(shù)只能單獨使用(寫成一個單獨語句), 而不能放在輸入或輸出連續(xù)表達式中,無法統(tǒng)一 輸入輸出操作的形式。 3 采用重載 和 運算符的方法,并將運算符 函數(shù)定義成被輸入或輸出對象類的友元函數(shù)。這種 方法將會消除前兩種方法所帶來的缺點,是一種遵 循面向?qū)ο笤O計原則的方法。,8.3.1 重載輸入運算符 輸入運算符 是輸入流類(將在第八章中詳細講 述)的成員函數(shù)。該運算符也是一個雙目運算符,它 的左操作數(shù)必須是輸入流類對象的引用,表示被輸入 的信息必須來自標準的輸入流設備;而右操作數(shù)是接 收輸入信息的指定類對象的引用。因此,為自定義類 重載的輸入運算符函數(shù)只能是類成員函數(shù)。,1 原
40、型 friend 輸入流類,2 定義 輸入流 ,3 調(diào)用 cin 類對象名; 例如: point pt; cin pt;,注意: 輸入運算符重載函數(shù)的第一個參數(shù)的類型必須是輸 入流類 istream 對象的引用,形參名(流對象名)可 以使用任何合法的標識符。 輸入運算符重載函數(shù)的第二個參數(shù)的類型必須是接 收輸入信息的指定類對象的引用,例如 point cout pt;,注意: 輸出運算符重載函數(shù)的第一個參數(shù)的類型必須是輸 出流類 ostream 對象的引用,形參名(流對象名)可 以使用任何合法的標識符。 輸出運算符重載函數(shù)的第二個參數(shù)的類型必須是輸 出信息的指定類對象或?qū)ο蟮囊?,例?poi
41、nt/ 輸入流對象 ofstream out;/ 輸出流對象 fstream io;/ 輸入輸出流對象,使用文件流類的成員函數(shù) open 打開文件,也就是 使某一個文件與指定流相關聯(lián)。open 的原型: void open( const char* szName, int mode, int nProt = filebuf:openprot ); 其中三個參數(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 ;,各個枚舉值所指定的打開方式的詳細含義: 追加方式 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. 二進制方式 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 訪問保護方式:整數(shù)值 nProt 指定了被打開文件的 訪問保護方式(文件的訪問類型)。從函數(shù)原型 中可以知道 nProt 的缺省值是 filebuf:openprot,該 值對于 UNIX 操作系統(tǒng)是 0 x644,即普通文件。在 DOS 或 Windows 操作系統(tǒng)中, nProt 的值通常對 應文件屬性,它們是: 0普通文件 1只讀文件 2隱含文件 4系統(tǒng)文件 8備份文件,4 調(diào)用實例 打開一個輸出文件 ofstream ou
47、t; out.open(test, ios:out, 0); 按普通文件訪問打開一個輸出文件 “test”,與輸 出文件流 out 相關聯(lián)。由于普通文件訪問方式 和輸出方式都是輸出文件流的缺省創(chuàng)建方式, 因此,調(diào)用 open 函數(shù)的形式可簡化為: out.open(test);, 打開一個輸入輸出文件 fstream both; both.open(test, ios:in | ios:out, 0); 由于文件流都提供具有打開文件功能的構(gòu)造函數(shù) (文件名、打開和訪問方式均可作為參數(shù)),所 以創(chuàng)建文件流對象和打開文件用可以一步完成: ofstream out(test); fstream bo
48、th(test, ios:in | ios:out, 0); 注意,文件打開操作是否成功應調(diào)用成員函數(shù) fail 進行檢查,避免對無效文件讀寫所引起的系統(tǒng)錯誤。,fstream both; both.open(test, ios:in | ios:out, 0); if (both.fail() cout Cannot open file! n; 錯誤處理語句 文件使用完畢后,應該關閉文件,并與所關聯(lián)的文 件流 “分離”。關閉文件使用文件流的成員函數(shù) close()。 例如: both.close();,8.4.2 文件的讀寫 1 文本文件的讀寫 一旦文件被成功打開,文件中的文本數(shù)據(jù)信息的讀
49、寫操作與控制臺文件信息的輸入輸出操作是完全一 致的。從流類庫的定義說明中我們知道可以用于文 本數(shù)據(jù)輸入和輸出的運算符 和 是分別在 輸入流類 istream 和輸出流類 ostream 中定義的,而 用于文件讀寫的流類 ifstream、ofstream 和 fstream 是 istream 和 ostream 的派生類,它們之間的層次關系 如下:,顯然, 和 也是 ifstream,ofstream 和 fstream 的運算符,但調(diào)用時,必須用 ifstream,ofstream 或 fstream 流類對象替代控制臺文本信息輸入輸出使用 的輸入流類對象(例如,cin)和輸出流類對象(例
50、 如,cout )。,istream,ostream,fstreambase,例8-5 把一個整數(shù)、一個浮點數(shù)和一個字符串以文本 形式寫入一個磁盤文件 test 中。顯然,該程序執(zhí) 行后,屏幕上是不會顯示任何與程序有關的信息 的。而程序產(chǎn)生的磁盤文件可以使用 DOS 系統(tǒng) 的 type 命令或使用 Windows 平臺的 “記事本” 或 其他可以讀寫純文本文件的工具查看。文件“test” 中記錄的信息為: 10 123.456 This is a text file.,例8-6 先建立一個輸出文件 “test2”,向它寫入數(shù)據(jù), 然后關閉文件,再按輸入模式打開 “test2” ,并 讀取和顯示
51、文件中的信息。 語句 fout 100 hex 100 endl; 使第二 個10進制 100 轉(zhuǎn)換為16進制表示的文本串寫入文 件 test2。使用 debug 程序可以看到文件中兩個數(shù) 據(jù)文本存儲格式: 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 進制 100,而是10 進制 64。如 果要使 j = 100,則需要將上述語句改為: fin str i hex j; 此時,程序執(zhí)行結(jié)果為: Hello! 100 100,例
52、8-7 從鍵盤讀入字符串、并將它們寫入磁盤。當用 戶輸入空白字符時,程序停止。 問題分析: 本程序采用了命令行參數(shù)的形式,執(zhí)行程序時, 命令行中除程序的執(zhí)行文件名外,還需要傳遞一 個參數(shù),即輸出文件名。因此命令行參數(shù)計數(shù) argc = 2, 執(zhí)行文件名保存在 argv0 中,而輸出文 件名被存放在 argv1 中。例如,輸出文件名為 file,則命令行應該是:write file 程序執(zhí)行時,首先在屏幕上顯示用戶輸入提示。 用戶從鍵盤輸入字符串,并寫入命令行指定的輸 出文件中,直至輸入 CTRL-Z,即 ASCII 碼 0 輸入停止,文件關閉,程序執(zhí)行結(jié)束。,2 二進制文件的讀寫 任何文件中無
53、論包含是文本數(shù)據(jù)還是二進制數(shù)據(jù), 都能以文本方式或二進制方式打開。這就是說,文 件的打開方式并不能保證文件數(shù)據(jù)的形式和含義, 而確保文件數(shù)據(jù)的形式和含義關鍵是如何對文件的 數(shù)據(jù)進行讀寫。二進制文件中的數(shù)據(jù)是直接將數(shù)據(jù) 在內(nèi)存中存放的形式映像到文件中,因此在讀寫過 程中不能發(fā)生任何轉(zhuǎn)換。顯然,這樣的讀寫操作是 不能使用輸入運算符 “” 和輸出運算符 “” 完成 的。對二進制文件的讀寫操作有兩種: 使用 get 函數(shù)和 put 函數(shù)讀寫單字節(jié); 使用 read 函數(shù)和 write 函數(shù)讀寫指定長度的字節(jié)。, 使用 get 函數(shù)和 put 函數(shù)讀寫二進制文件 get 是 istream 類的成員函數(shù)
54、。函數(shù)原型: inline istream,功能:從輸入流對象關聯(lián)的文件中讀數(shù)據(jù), 每次讀1字節(jié),讀指針自動增1。 put 是 ostream 類的成員函數(shù)。函數(shù)原型 inline ostream 功能:向輸出流對象關聯(lián)的文件中寫數(shù)據(jù), 每次寫1字節(jié),寫指針自動增1。,例8-8一個實現(xiàn)任意文件復制的簡單程序。 問題分析: 與例8-7相同也采用了命令行參數(shù)的形式,所 不同的是在執(zhí)行程序時,命令行中應包含執(zhí)行 文件名,源文件名和目標文件名。因此命令行 參數(shù)計數(shù) argc = 3,執(zhí)行文件名保存在 argv0 中,源文件名存放在 argv1 中,目標文件名 存放在 argv2 中。若執(zhí)行文件名為 d
55、uplicate, 源文件名為 file,目標文件名為 file1,則執(zhí)行 時的命令行應該是:duplicate file file1 如果命令行的參數(shù)個數(shù)不等于3,則顯示命令 行格式提示并退出執(zhí)行。, 二進制文件的處理過程與文本文件的處理過 程基本相同,但判斷文件結(jié)束時有所區(qū)別: 文本文件:遇到文件結(jié)束符,get 函數(shù)返回文 件結(jié)束標志EOF,該標志值為 -1,它有別 于其它任何文本字符。 二進制文件:由于 -1 也是有效二進制數(shù)據(jù), 所以不能使用 EOF 作為判斷文件結(jié)束的標 志。為解決這個問題,應使用另一個成員 函數(shù) eof,用來判斷文件結(jié)束,其原型為: int eof(); 當?shù)竭_文件
56、尾時,它返回 bool 值 true,否 則返回 false。,例8-9實現(xiàn)在屏幕上顯示任何文件的內(nèi)容。 注意:指定文件打開方式為 ios:binary 并不是按 二進制讀寫文件數(shù)據(jù)的必要條件。如果不存在對 二進制文件的特定判別問題,就不一定需要使用 ios:binary 方式打開文件。在例8-8和例8-9中,都 沒有指定文件打開方式為 ios:binary。, 使用 read 函數(shù)和 write 函數(shù)讀寫二進制文件 read 是 istream 類的成員函數(shù)。函數(shù)原型: istream 功能:從相應的流中讀取 num 個字節(jié),并將 它們存放到指針 buf 所指的緩沖區(qū)中, 讀指針自動增加 n
57、um 。 在調(diào)用該函數(shù)時,需要傳遞兩個參數(shù):緩沖 區(qū)的首地址和從文件中讀取的字節(jié)數(shù),,其調(diào)用格式如下: read(緩沖區(qū)首址, 讀入的字節(jié)數(shù)); 注意:“緩沖區(qū)”的數(shù)據(jù)類型為 unsigned char, 如果讀取的數(shù)據(jù)為其他類型時,則須進行類 型轉(zhuǎn)換,例如: int array = 50, 60, 70; read(usigned char*), write 是 ostream 類的成員函數(shù)。函數(shù)原型: ostream 功能:從 buf 所指向的緩沖區(qū)中將 num 個字節(jié) 寫到相應的文件中。寫指針自動增加 num。 在調(diào)用該函數(shù)時,所需參數(shù)與 read 類似。,例8-10 用 write 函數(shù)向文件 “test” 中寫入雙精度數(shù) 與字符串。 顯然,該程序執(zhí)行后,屏幕上將不會顯示任何信 息,而且不能使用 DOS 系統(tǒng)的 type 命令或使用 Windows 平臺的 “記事本” 或其他可以讀寫純
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 工業(yè)用石材采購安全措施
- 江蘇省南京市浦口區(qū)江浦高級中學2025年高二物理第二學期期末經(jīng)典試題含解析
- 2025年福州市八縣協(xié)作校物理高一第二學期期末復習檢測模擬試題含解析
- 汽車零配件成品保護方案措施
- 能源行業(yè)信息技術能力提升個人研修計劃
- School Psychologists as Advocates for Social Justice (Chapter 20)英漢翻譯實踐報告
- 大型展館施工進度計劃及施工管理措施
- 2025一年級下冊科學期末復習計劃
- 商洛市重點中學2024年八上物理期末預測試題含解析
- 華南農(nóng)業(yè)大學珠江學院《鋼結(jié)構(gòu)設計原理》2023-2024學年第一學期期末試卷
- 充電樁項目實施過程中的質(zhì)量保證措施
- T-CPUMT 025-2024 工業(yè)互聯(lián)網(wǎng)平臺 服務通.用要求
- 2025年度地質(zhì)勘探監(jiān)理服務合同范本
- 保山隆陽區(qū)小升初數(shù)學試卷
- 2025年上半年北京市西城區(qū)教委事業(yè)單位公開招聘考試筆試易考易錯模擬試題(共500題)試卷后附參考答案
- RoHS知識培訓課件
- 2024-2025學年北京西城區(qū)高一(上)期末語文試卷(含答案)
- 2025年貴州貴旅集團雷山文化旅游產(chǎn)業(yè)發(fā)展有限責任公司招聘筆試參考題庫附帶答案詳解
- 2024年初升高數(shù)學銜接教材講義
- 血小板減少護理查房課件
- 人教版(2024)數(shù)學七年級上冊期末測試卷(含答案)
評論
0/150
提交評論