C++的iostream標(biāo)準(zhǔn)庫介紹
作者:管寧0 為什么需要iostream
我們從一開始就一直在利用C++的輸入輸出在做著各種練習(xí),輸入輸出是由iostream庫提供的,所以討論此標(biāo)準(zhǔn)庫是有必要的,它與C語言的 stdio庫不同,它從一開始就是用多重繼承與虛擬繼承實(shí)現(xiàn)的面向?qū)ο蟮膶哟谓Y(jié)構(gòu),作為一個(gè)c++的標(biāo)準(zhǔn)庫組件提供給程序員使用。iostream為內(nèi)置類型類型對(duì)象提供了輸入輸出支持,同時(shí)也支持文件的輸入輸出,類的設(shè)計(jì)者可以通過對(duì)iostream庫的擴(kuò)展,來支持自定義類型的輸入輸出操作。
為什么說要擴(kuò)展才能提供支持呢?我們來一個(gè)示例。
#include?<stdio.h>?
#include?<iostream>?
using?namespace?std;?????
class?Test?
{?
????????public:?
????????Test(int?a=0,int?b=0)?
????????
{?
????????????????Test::a=a;?
????????????????Test::b=b;?
????????}?
????????int?a;?
????????int?b;?
};?
int?main()?
{?
????????Test?t(100,50);?
????????printf("%???",t);//不明確的輸出格式?
????????scanf("%???",t);//不明確的輸入格式?
????????cout<<t<<endl;//同樣不夠明確?
????????cin>>t;//同樣不夠明確?
????????system("pause");?
}
在上例中我們之所以用printf與cout進(jìn)行對(duì)比目的是為了告訴大家,C與C++處理輸入輸出的根本不同,我們從c遠(yuǎn)的輸入輸出可以很明顯看出是函數(shù)調(diào)用方式,而c++的則是對(duì)象模式,cout和cin是ostream類和istream類的對(duì)象。
1 iostream: istream 和 ostream
C++中的iostream庫主要包含下圖所示的幾個(gè)頭文件:IOSstream 庫 | |
---|---|
fstream | iomainip |
ios | iosfwd |
iostream | istream |
ostream | sstream |
streambuf | strstream |
我們所熟悉的輸入輸出操作分別是由istream(輸入流)和ostream(輸出流)這兩個(gè)類提供的,為了允許雙向的輸入/輸出,由istream和ostream派生出了iostream類。
類的繼承關(guān)系見下圖:
iostream庫定義了以下三個(gè)標(biāo)準(zhǔn)流對(duì)象:
- cin,表示標(biāo)準(zhǔn)輸入(standard input)的istream類對(duì)象。cin使我們可以從設(shè)備讀如數(shù)據(jù)。
- cout,表示標(biāo)準(zhǔn)輸出(standard output)的ostream類對(duì)象。cout使我們可以向設(shè)備輸出或者寫數(shù)據(jù)。
- cerr,表示標(biāo)準(zhǔn)錯(cuò)誤(standard error)的osttream類對(duì)象。cerr是導(dǎo)出程序錯(cuò)誤消息的地方,它只能允許向屏幕設(shè)備寫數(shù)據(jù)。
輸出主要由重載的左移操作符(<<)來完成,輸入主要由重載的右移操作符(>>)完成:
- >>a表示將數(shù)據(jù)放入a對(duì)象中。
- <<a表示將a對(duì)象中存儲(chǔ)的數(shù)據(jù)拿出。
這些標(biāo)準(zhǔn)的流對(duì)象都有默認(rèn)的所對(duì)應(yīng)的設(shè)備,見下表:
C++對(duì)象名 | 設(shè)備名稱 | C中標(biāo)準(zhǔn)設(shè)備名 | 默認(rèn)含義 |
---|---|---|---|
cin | 鍵盤 | stdin | 標(biāo)準(zhǔn)輸入 |
cout | 顯示器屏幕 | stdout | 標(biāo)準(zhǔn)輸出 |
cerr | 顯示器屏幕 | stderr | 標(biāo)準(zhǔn)錯(cuò)誤輸出 |
那么原理上C++有是如何利用cin/cout對(duì)象與左移和右移運(yùn)算符重載來實(shí)現(xiàn)輸入輸出的呢?
下面我們以輸出為例,說明其實(shí)現(xiàn)原理:
- cout是ostream類的對(duì)象,因?yàn)樗赶虻氖菢?biāo)準(zhǔn)設(shè)備(顯示器屏幕),所以它在iostream頭文件中作為全局對(duì)象進(jìn)行定義。
- ostream cout(stdout);//其默認(rèn)指向的C中的標(biāo)準(zhǔn)設(shè)備名,作為其構(gòu)造函數(shù)的參數(shù)使用。
- 在iostream.h頭文件中,ostream類對(duì)應(yīng)每個(gè)基本數(shù)據(jù)類型都有其友元函數(shù)對(duì)左移操作符進(jìn)行了友元函數(shù)的重載。
- ostream& operator<<(ostream &temp,int source);
- ostream& operator<<(ostream &temp,char *ps);
- ... 等等
一句輸出語句:cout<<"www.cndev-lab.com";,事實(shí)上調(diào)用的就是ostream& operator<<(ostream &temp,char *ps);這個(gè)運(yùn)算符重載函數(shù),由于返回的是流對(duì)象的引用,引用可以作為左值使用,所以當(dāng)程序中有類似cout<<"www.cndev- lab.com"<<"中國軟件開發(fā)實(shí)驗(yàn)室";這樣的語句出現(xiàn)的時(shí)候,就能夠構(gòu)成連續(xù)輸出。
由于iostream庫不光支持對(duì)象的輸入輸出,同時(shí)也支持文件流的輸入輸出,所以在詳細(xì)講解左移與右移運(yùn)算符重載只前,我們有必要先對(duì)文件的輸入輸出以及輸入輸出的控制符有所了解。
2 fstream: ifstream 和 ofstream
和文件有關(guān)系的輸入輸出類主要在fstream.h這個(gè)頭文件中被定義,在這個(gè)頭文件中主要被定義了三個(gè)類,由這三個(gè)類控制對(duì)文件的各種輸入輸出操作,他們分別是ifstream、ofstream、fstream,其中fstream類是由iostream類派生而來,他們之間的繼承關(guān)系見下圖所示。
由于文件設(shè)備并不像顯示器屏幕與鍵盤那樣是標(biāo)準(zhǔn)默認(rèn)設(shè)備,所以它在fstream.h頭文件中是沒有像cout那樣預(yù)先定義的全局對(duì)象,所以我們必須自己定義一個(gè)該類的對(duì)象,我們要以文件作為設(shè)備向文件輸出信息(也就是向文件寫數(shù)據(jù)),那么就應(yīng)該使用ofstream類。
ofstream類的默認(rèn)構(gòu)造函數(shù)原形為:
ofstream::ofstream(constchar *filename,int mode = ios::out,int openprot = filebuf::openprot);
- filename: 要打開的文件名
- mode: 要打開文件的方式
- prot: 打開文件的屬性
其中mode和openprot這兩個(gè)參數(shù)的可選項(xiàng)表見下表:
mode屬性表 | |
ios::app | 以追加的方式打開文件 |
ios::ate | 文件打開后定位到文件尾,ios:app就包含有此屬性 |
ios::binary | 以二進(jìn)制方式打開文件,缺省的方式是文本方式。兩種方式的區(qū)別見前文 |
ios::in | 文件以輸入方式打開 |
ios::out | 文件以輸出方式打開 |
ios::trunc | 如果文件存在,把文件長度設(shè)為0 |
openprot屬性表 | |
屬性 | 含義 |
0 | 普通文件,打開訪問 |
1 | 只讀文件 |
2 | 隱含文件 |
4 | 系統(tǒng)文件 |
實(shí)例代碼如下:
#include?<fstream>?
using?namespace?std;?
int?main()??
{?
????????ofstream?myfile("c:\\1.txt",ios::out|ios::trunc,0);?
????????myfile<<"中國軟件開發(fā)實(shí)驗(yàn)室"<<endl<<"網(wǎng)址:"<<"www.cndev-lab.com";?
????????myfile.close()?
????????system("pause");?
}
ios::app為追加模式,在使用追加模式的時(shí)候同時(shí)進(jìn)行文件狀態(tài)的判斷是一個(gè)比較好的習(xí)慣。
示例如下:
#include?<iostream>?
#include?<fstream>?
using?namespace?std;?
int?main()??
{?
????????ofstream?myfile("c:\\1.txt",ios::app,0);?
????????if(!myfile)//或者寫成myfile.fail()?
????????
{?
????????????????cout<<"文件打開失敗,目標(biāo)文件狀態(tài)可能為只讀!";?
????????????????system("pause");?
????????????????exit(1);?
????????}?
????????myfile<<"中國軟件開發(fā)實(shí)驗(yàn)室"<<endl<<"網(wǎng)址:"<<"www.cndev-lab.com"<<endl;?
????????myfile.close();?
}
在定義ifstream和ofstream類對(duì)象的時(shí)候,我們也可以不指定文件。以后可以通過成員函數(shù)open()顯式的把一個(gè)文件連接到一個(gè)類對(duì)象上。
例如:
#include?<iostream>?
#include?<fstream>?
using?namespace?std;?
int?main()??
{?
????????ofstream?myfile;?
????????myfile.open("c:\\1.txt",ios::out|ios::app,0);?
????????if(!myfile)//或者寫成myfile.fail()?
????????
{?
????????????????cout<<"文件創(chuàng)建失敗,磁盤不可寫或者文件為只讀!";?
????????????????system("pause");?
????????????????exit(1);?
????????}?
????????myfile<<"中國軟件開發(fā)實(shí)驗(yàn)室"<<endl<<"網(wǎng)址:"<<"www.cndev-lab.com"<<endl;?
????????myfile.close();?
}
代碼如下:
#include?<iostream>?
#include?<fstream>?
#include?<string>?
using?namespace?std;?
int?main()??
{?
????????ifstream?myfile;?
????????myfile.open("c:\\1.txt",ios::in,0);?
????????if(!myfile)?
????????
{?
????????????????cout<<"文件讀錯(cuò)誤";?
????????????????system("pause");?
????????????????exit(1);?
????????}?
????????char?ch;?
????????string?content;?
????????while(myfile.get(ch))?
????????
{?
????????????????content+=ch;?
????????????????cout.put(ch);//cout<<ch;這么寫也是可以的?
????????}?
????????myfile.close();?
????????cout<<content;?
????????system("pause");?
}
我們?cè)诤唵谓榻B過ofstream類和ifstream類后,我們?cè)賮砜匆幌耭stream類,fstream類是由iostream派生而來,fstream類對(duì)象可以同對(duì)文件進(jìn)行讀寫操作。
示例代碼如下:
#include?<iostream>?
#include?<fstream>?
using?namespace?std;?
int?main()??
{?
????????fstream?myfile;?
????????myfile.open("c:\\1.txt",ios::out|ios::app,0);?
????????if(!myfile)?
????????
{?
????????????????cout<<"文件寫錯(cuò)誤,文件屬性可能為只讀!"<<endl;?
????????????????system("pause");?
????????????????exit(1);?
????????}?
????????myfile<<"中國軟件開發(fā)實(shí)驗(yàn)室"<<endl<<"網(wǎng)址:"<<"www.cndev-lab.com"<<endl;???
????????myfile.close();?
????????
????????myfile.open("c:\\1.txt",ios::in,0);?
????????if(!myfile)?
????????
{?
????????????????cout<<"文件讀錯(cuò)誤,文件可能丟失!"<<endl;?
????????????????system("pause");?
????????????????exit(1);?
????????}?
????????char?ch;?
????????while(myfile.get(ch))?
????????
{?
????????????????cout.put(ch);?
????????}?
????????myfile.close();?
????????system("pause");?
}
接下來我們來學(xué)習(xí)一下串流類的基礎(chǔ)知識(shí),什么叫串流類?
3 strstream: ostrstream 和 istrstream
簡單的理解就是能夠控制字符串類型對(duì)象進(jìn)行輸入輸出的類,C++不光可以支持C++風(fēng)格的字符串流控制,還可以支持C風(fēng)格的字符串流控制。我們先看看看C++是如何對(duì)C風(fēng)格的字符串流進(jìn)行控制的,C中的字符串其實(shí)也就是字符數(shù)組,字符數(shù)組內(nèi)的數(shù)據(jù)在內(nèi)存中的位置的排列是連續(xù)的,我們通常用 char str[size]或者char *str的方式聲明創(chuàng)建C風(fēng)格字符數(shù)組,為了能讓字符數(shù)組作為設(shè)備并提供輸入輸出操作,C++引入了ostrstream、istrstream、 strstream這三個(gè)類,要使用他們創(chuàng)建對(duì)象就必須包含strstream.h頭文件。
- istrstream類用于執(zhí)行C風(fēng)格的串流的輸入操作,也就是以字符串?dāng)?shù)組作為輸入設(shè)備。
- ostrstream類用于執(zhí)行C風(fēng)格的串流的輸出操作,也就是一字符串?dāng)?shù)組作為輸出設(shè)備。
- strstream類同時(shí)可以支持C風(fēng)格的串流的輸入輸出操作。
istrstream類是從istream(輸入流類)和strstreambase(字符串流基類)派生而來,ostrstream是從 ostream(輸出流類)和strstreambase(字符串流基類)派生而來,strstream則是從iostream(輸入輸出流類)和和 strstreambase(字符串流基類)派生而來。
他們的繼承關(guān)系如下圖所示:
串流同樣不是標(biāo)準(zhǔn)設(shè)備,不會(huì)有預(yù)先定義好的全局對(duì)象,所以不能直接操作,需要通過構(gòu)造函數(shù)創(chuàng)建對(duì)象。
類istrstream的構(gòu)造函數(shù)原形如下:
istrstream::istrstream(constchar *str,int size);
下面的示例代碼就是利用istrstream類創(chuàng)建類對(duì)象,制定流輸入設(shè)備為字符串?dāng)?shù)組,通過它向一個(gè)字符型對(duì)象輸入數(shù)據(jù)。代碼如下:
#include?<iostream>?
#include?<strstream>?
using?namespace?std;?
int?main()??
{?
????????char?*name?=?"www.cndev-lab.com";?
????????int?arraysize?=?strlen(name)+1;?
????????istrstream?is(name,arraysize);?
????????char?temp;?
????????is>>temp;?
????????cout<<temp;?
????????system("pause");?
}
ostrstream::ostrstream(char *_Ptr,int streamsize,int Mode = ios::out);
我們來一個(gè)示例代碼:
#include?<iostream>?
#include?<strstream>?
using?namespace?std;?
int?main()??
{?
????????int?arraysize=1;?
????????char?*pbuffer=new?char[arraysize];?
????????ostrstream?ostr(pbuffer,arraysize,ios::out);?
????????ostr<<arraysize<<ends;//使用ostrstream輸出到流對(duì)象的時(shí)候,要用ends結(jié)束字符串?
????????cout<<pbuffer;?
????????delete[]?pbuffer;?
????????system("pause");?
}
4 stringstream
對(duì)于stringstream了來說,不用我多說,大家也已經(jīng)知道它是用于C++風(fēng)格的字符串的輸入輸出的。 stringstream的構(gòu)造函數(shù)原形如下:stringstream::stringstream(string?str);
#include?<iostream>?
#include?<sstream>?
#include?<string>?
using?namespace?std;?
int?main()??
{?
????????stringstream?ostr("ccc");?
????????ostr.put('d');?
????????ostr.put('e');?
????????ostr<<"fg";?
????????string?gstr?=?ostr.str();?
????????cout<<gstr<<endl;?
????????
????????char?a;?
????????ostr>>a;?
????????cout<<a?
????????
????????system("pause");?
}
#include?<iostream>?
#include?<sstream>?
#include?<string>?
using?namespace?std;?
int?main()??
{?
????????stringstream?sstr;?
????????//--------int轉(zhuǎn)string-----------?
????????int?a=100;?
????????string?str;?
????????sstr<<a;?
????????sstr>>str;?
????????cout<<str<<endl;?
????????//--------string轉(zhuǎn)char[]--------?
????????sstr.clear();//如果你想通過使用同一stringstream對(duì)象實(shí)現(xiàn)多種類型的轉(zhuǎn)換,請(qǐng)注意在每一次轉(zhuǎn)換之后都必須調(diào)用clear()成員函數(shù)。?
????????string?name?=?"colinguan";?
????????char?cname[200];?
????????sstr<<name;?
????????sstr>>cname;?
????????cout<<cname;?
????????system("pause");?
}
5 io_state 輸入/輸出的狀態(tài)標(biāo)志
C++中負(fù)責(zé)的輸入/輸出的系統(tǒng)包括了關(guān)于每一個(gè)輸入/輸出操作的結(jié)果的記錄信息。這些當(dāng)前的狀態(tài)信息被包含在io_state類型的對(duì)象中。io_state是一個(gè)枚舉類型(就像open_mode一樣),以下便是它包含的值。- goodbit 無錯(cuò)誤
- Eofbit 已到達(dá)文件尾
- failbit 非致命的輸入/輸出錯(cuò)誤,可挽回
- badbit 致命的輸入/輸出錯(cuò)誤,無法挽回
有兩種方法可以獲得輸入/輸出的狀態(tài)信息。一種方法是通過調(diào)用rdstate()函數(shù),它將返回當(dāng)前狀態(tài)的錯(cuò)誤標(biāo)記。例如,假如沒有任何錯(cuò)誤,則rdstate()會(huì)返回goodbit.下例示例,表示出了rdstate()的用法:
#include?<iostream>?
using?namespace?std;?
int?main()??
{?
????????int?a;?
????????cin>>a;?
????????cout<<cin.rdstate()<<endl;?
????????if(cin.rdstate()?==?ios::goodbit)?
????????
{?
????????????????cout<<"輸入數(shù)據(jù)的類型正確,無錯(cuò)誤!"<<endl;?
????????}?
????????if(cin.rdstate()?==?ios_base::failbit)?
????????
{?
????????????????cout<<"輸入數(shù)據(jù)類型錯(cuò)誤,非致命錯(cuò)誤,可清除輸入緩沖區(qū)挽回!"<<endl;?
????????}?
????????system("pause");?
}
bool?bad();
bool?eof();
bool?fail();
bool?good();
下例示例,表示出了上面各成員函數(shù)的用法:
#include?<iostream>?
using?namespace?std;?
int?main()??
{?
????????int?a;?
????????cin>>a;?
????????cout<<cin.rdstate()<<endl;?
????????if(cin.good())?
????????
{?
????????????????cout<<"輸入數(shù)據(jù)的類型正確,無錯(cuò)誤!"<<endl;?
????????}?
????????if(cin.fail())?
????????
{?
????????????????cout<<"輸入數(shù)據(jù)類型錯(cuò)誤,非致命錯(cuò)誤,可清除輸入緩沖區(qū)挽回!"<<endl;?
????????}?
????????system("pause");?
}
示例代碼如下:
#include?<iostream>?
using?namespace?std;?
int?main()??
{?
????????int?a;?
????????cin>>a;?
????????cout<<cin.rdstate()<<endl;?
????????cin.clear(ios::goodbit);?
????????cout<<cin.rdstate()<<endl;?
????????system("pause");?
}
示例代碼如下:
#include?<iostream>?
using?namespace?std;?
int?main()??
{?
????????int?a;?
????????while(1)?
????????
{?
????????????????cin>>a;?
????????????????if(!cin)//條件可改寫為cin.fail()?
????????????????
{?
????????????????????????cout<<"輸入有錯(cuò)!請(qǐng)重新輸入"<<endl;?
????????????????????????cin.clear();?
????????????????????????cin.get();?
????????????????}?
????????????????else?
????????????????
{?
????????????????????????cout<<a;?
????????????????????????break;?
????????????????}?
????????}?
????????system("pause");?
}
#include?<iostream>?
#include?<fstream>?
using?namespace?std;?
int?main()??
{?
????????ifstream?myfile("c:\\1.txt",ios_base::in,0);?
????????if(myfile.fail())?
????????
{?
????????????????cout<<"文件讀取失敗或指定文件不存在!"<<endl;?
????????}?
????????else?
????????
{?
????????????????char?ch;?
????????????????while(myfile.get(ch))?
????????????????
{?
????????????????????????cout<<ch;?
????????????????}?
????????????????if(myfile.eof())?
????????????????
{?
????????????????????????cout<<"文件內(nèi)容已經(jīng)全部讀完"<<endl;?
????????????????}?
????????????????while(myfile.get(ch))?
????????????????
{?
????????????????????????cout<<ch;?
????????????????}?
????????}?
????????system("pause");?
}
未完待續(xù)……
posted on 2006-04-25 22:38 楊粼波 閱讀(492) 評(píng)論(0) 編輯 收藏 引用 所屬分類: 文章收藏