C++的iostream標準庫介紹

來源:互聯網
上載者:User
為什麼需要iostream 我們從一開始就一直在利用C++的輸入輸出在做著各種練習,輸入輸出是由iostream庫提供的,所以討論此標準庫是有必要的,它與C語言的 stdio庫不同,它從一開始就是用多重繼承與虛擬繼承實現的物件導向的階層,作為一個c++的標準庫組件提供給程式員使用。

  iostream為內建類型類型對象提供了輸入輸出支援,同時也支援檔案的輸入輸出,類的設計者可以通過對iostream庫的擴充,來支援自訂類型的輸入輸出操作。

  為什麼說要擴充才能提供支援呢?我們來一個樣本。

#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");}

  由於自訂類的特殊性,在上面的代碼中,無論你使用c風格的輸入輸出,或者是c++的輸入輸出都不是不明確的一個表示,由於c語言沒有運算子多載機制,導致stdio庫的不可擴充性,讓我們無法讓printf()和scanf()支援對自訂類對象的擴充識別,而c++是可以通過運算子多載機制擴充 iostream庫的,使系統能能夠識別自訂類型,從而讓輸入輸出明確的知道他們該幹什麼,格式是什麼。

  在上例中我們之所以用printf與cout進行對比目的是為了告訴大家,C與C++處理輸入輸出的根本不同,我們從c遠的輸入輸出可以很明顯看出是函數調用方式,而c++的則是對象模式,cout和cin是ostream類和istream類的對象。

1 iostream: istream 和 ostream

  C++中的iostream庫主要包含所示的幾個標頭檔:

IOSstream 庫
fstream iomainip
ios iosfwd
iostream istream
ostream sstream
streambuf strstream

  我們所熟悉的輸入輸出操作分別是由istream(輸入資料流)和ostream(輸出資料流)這兩個類提供的,為了允許雙向的輸入/輸出,由istream和ostream派生出了iostream類。

  類的繼承關係見:

iostream庫定義了以下三個標準流對象:

  1. cin,表示標準輸入(standard input)的istream類對象。cin使我們可以從裝置讀如資料。
  2. cout,表示標準輸出(standard output)的ostream類對象。cout使我們可以向裝置輸出或者寫資料。
  3. cerr,表示標準錯誤(standard error)的osttream類對象。cerr是匯出程式錯誤訊息的地方,它只能允許向螢幕裝置寫資料。

  輸出主要由重載的左移操作符(<<)來完成,輸入主要由重載的右移操作符(>>)完成:

  1. >>a表示將資料放入a對象中。
  2. <<a表示將a對象中儲存的資料拿出。

  這些標準的流對象都有預設的所對應的裝置,見下表:

C++對象名 裝置名稱 C中標準裝置名稱 預設含義
cin 鍵盤 stdin 標準輸入
cout 顯示器螢幕 stdout 標準輸出
cerr 顯示器螢幕 stderr 標準錯誤輸出

  上表中的意思表明cin對象的預設輸入裝置是鍵盤,cout對象的預設輸出裝置是顯示器螢幕。

  那麼原理上C++有是如何利用cin/cout對象與左移和右移運算子多載來實現輸入輸出的呢?

  下面我們以輸出為例,說明其實現原理:

  1. cout是ostream類的對象,因為它所指向的是標準裝置(顯示器螢幕),所以它在iostream標頭檔中作為全域對象進行定義。
  2. ostream cout(stdout);//其預設指向的C中的標準裝置名稱,作為其建構函式的參數使用。
  3. 在iostream.h標頭檔中,ostream類對應每個基礎資料型別 (Elementary Data Type)都有其友元函數對左移操作符進行了友元函數的重載。
    • ostream& operator<<(ostream &temp,int source);
    • ostream& operator<<(ostream &temp,char *ps);
    • ... 等等

  一句輸出語句:cout<<"www.cndev-lab.com";,事實上調用的就是ostream& operator<<(ostream &temp,char *ps);這個運算子多載函數,由於返回的是流對象的引用,引用可以作為左值使用,所以當程式中有類似cout<<"www.cndev- lab.com"<<"中國軟體開發實驗室";這樣的語句出現的時候,就能夠構成連續輸出。

  由於iostream庫不光支援對象的輸入輸出,同時也支援檔案流的輸入輸出,所以在詳細講解左移與右移運算子多載只前,我們有必要先對檔案的輸入輸出以及輸入輸出的控制符有所瞭解。

2 fstream: ifstream 和 ofstream

  和檔案有關係的輸入輸出類主要在fstream.h這個標頭檔中被定義,在這個標頭檔中主要被定義了三個類,由這三個類控制對檔案的各種輸入輸出操作,他們分別是ifstream、ofstream、fstream,其中fstream類是由iostream類派生而來,他們之間的繼承關係見所示。

由於檔案裝置並不像顯示器螢幕與鍵盤那樣是標準預設裝置,所以它在fstream.h標頭檔中是沒有像cout那樣預先定義的全域對象,所以我們必須自己定義一個該類的對象,我們要以檔案作為裝置向檔案輸出資訊(也就是向檔案寫資料),那麼就應該使用ofstream類。

  ofstream類的預設建構函式原形為:

  ofstream::ofstream(const char *filename,int mode = ios::out,int openprot = filebuf::openprot);
  • filename:  要開啟的檔案名稱
  • mode:    要開啟檔案的方式
  • prot:    開啟檔案的屬性

  其中mode和openprot這兩個參數的可選項表見下表:

mode屬性工作表
ios::app 以追加的方式開啟檔案
ios::ate 檔案開啟後定位到檔案尾,ios:app就包含有此屬性
ios::binary 以二進位方式開啟檔案,預設的方式是文本方式。兩種方式的區別見前文
ios::in 檔案以輸入方式開啟
ios::out 檔案以輸出方式開啟
ios::trunc 如果檔案存在,把檔案長度設為0

  可以用“或”把以上屬性串連起來,如ios::out|ios::binary。

openprot屬性工作表
屬性 含義
0 普通檔案,開啟訪問
1 唯讀檔案
2 隱含檔案
4 系統檔案

  可以用“或”或者“+”把以上屬性串連起來 ,如3或1|2就是以唯讀和隱含屬性開啟檔案。

執行個體代碼如下:

#include <fstream>using namespace std;int main(){ofstream myfile("c:\\1.txt",ios::out|ios::trunc,0);myfile<<"中國軟體開發實驗室"<<endl<<"網址:"<<"www.cndev-lab.com";myfile.close()system("pause");}

  檔案使用完後可以使用close成員函數關閉檔案。

  ios::app為追加模式,在使用追加模式的時候同時進行檔案狀態的判斷是一個比較好的習慣。

  樣本如下:

#include <iostream>#include <fstream>using namespace std;int main(){ofstream myfile("c:\\1.txt",ios::app,0);if(!myfile)//或者寫成myfile.fail() {cout<<"檔案開啟失敗,目標檔案狀態可能為唯讀!";system("pause");exit(1);}myfile<<"中國軟體開發實驗室"<<endl<<"網址:"<<"www.cndev-lab.com"<<endl;myfile.close();}

  在定義ifstream和ofstream類對象的時候,我們也可以不指定檔案。以後可以通過成員函數open()顯式的把一個檔案串連到一個類對象上。

  例如:

#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<<"檔案建立失敗,磁碟不可寫或者檔案為唯讀!";system("pause");exit(1);}myfile<<"中國軟體開發實驗室"<<endl<<"網址:"<<"www.cndev-lab.com"<<endl;myfile.close();}

  下面我們來看一下是如何利用ifstream類對象,將檔案中的資料讀取出來,然後再輸出到標準裝置中的例子。

  代碼如下:

#include <iostream>#include <fstream>#include <string>using namespace std;int main(){ifstream myfile;myfile.open("c:\\1.txt",ios::in,0);if(!myfile){cout<<"檔案讀錯誤";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");}

  上例中,我們利用成員函數get(),逐一的讀取檔案中的有效字元,再利用put()成員函數,將檔案中的資料通過迴圈逐一輸出到標準裝置(螢幕)上, get()成員函數會在檔案讀到默尾的時候返回假值,所以我們可以利用它的這個特性作為while迴圈的終止條件,我們同時也在上例中引入了C++風格的字串類型string,在迴圈讀取的時候逐一儲存到content中,要使用string類型,必須包含string.h的標頭檔。

我們在簡單介紹過ofstream類和ifstream類後,我們再來看一下fstream類,fstream類是由iostream派生而來,fstream類對象可以同對檔案進行讀寫操作。

  範例程式碼如下:

#include <iostream>#include <fstream>using namespace std;int main(){fstream myfile;myfile.open("c:\\1.txt",ios::out|ios::app,0);if(!myfile){cout<<"檔案寫錯誤,檔案屬性可能為唯讀!"<<endl;system("pause");exit(1);}myfile<<"中國軟體開發實驗室"<<endl<<"網址:"<<"www.cndev-lab.com"<<endl;myfile.close();myfile.open("c:\\1.txt",ios::in,0);if(!myfile){cout<<"檔案讀錯誤,檔案可能丟失!"<<endl;system("pause");exit(1);}char ch;while(myfile.get(ch)){cout.put(ch);}myfile.close();system("pause");}

  由於fstream類可以對檔案同時進行讀寫操作,所以對它的對象進行初始話的時候一定要顯式的指定mode和openprot參數。

  接下來我們來學習一下串流類的基礎知識,什麼叫串流類?

3 strstream: ostrstream 和 istrstream

  簡單的理解就是能夠控制字元串類型對象進行輸入輸出的類,C++不光可以支援C++風格的字串流量控制,還可以支援C風格的字串流量控制。

  我們先看看看C++是如何對C風格的字串流進行控制的,C中的字串其實也就是字元數組,字元數組內的資料在記憶體中的位置的排列是連續的,我們通常用 char str[size]或者char *str的方式聲明建立C風格字元數組,為了能讓字元數組作為裝置並提供輸入輸出操作,C++引入了ostrstream、istrstream、 strstream這三個類,要使用他們建立對象就必須包含strstream.h標頭檔。

  • istrstream類用於執行C風格的串流的輸入操作,也就是以字串數組作為輸入裝置。
  • ostrstream類用於執行C風格的串流的輸出操作,也就是一字串數組作為輸出裝置。
  • strstream類同時可以支援C風格的串流的輸入輸出操作。

  istrstream類是從istream(輸入資料流類)和strstreambase(字串流基類)派生而來,ostrstream是從 ostream(輸出資料流類)和strstreambase(字串流基類)派生而來,strstream則是從iostream(輸入輸出資料流類)和和 strstreambase(字串流基類)派生而來。

  他們的繼承關係如所示:

  串流同樣不是標準裝置,不會有預先定義好的全域對象,所以不能直接操作,需要通過建構函式建立對象。

類istrstream的建構函式原形如下:

  istrstream::istrstream(const char *str,int size);

  參數1表示字串數組,而參數2表示數組大小,當size為0時,表示istrstream類對象直接連接到由str所指向的記憶體空間並以\0結尾的字串。

  下面的範例程式碼就是利用istrstream類建立類對象,制定流輸入裝置為字串數組,通過它向一個字元型對象輸入資料。代碼如下:

#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::ostrstream(char *_Ptr,int streamsize,int Mode = ios::out);

  第一個參數是字元數組,第二個是說明數組的大小,第三個參數是指開啟檔案。

  我們來一個範例程式碼:

#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輸出到流對象的時候,要用ends結束字串 cout<<pbuffer;delete[] pbuffer;system("pause");}

  上面的代碼中,我們建立一個c風格的串流輸出對象ostr,我們將arraysize內的資料成功的以字串的形式輸出到了ostr對象所指向的pbuffer指標的堆空間中,pbuffer也正是我們要輸出的字串數組,在結尾要使用ends結束字串,如果不這麼做就有溢出的危險。

4 stringstream

對於stringstream了來說,不用我多說,大家也已經知道它是用於C++風格的字串的輸入輸出的。  stringstream的建構函式原形如下:

  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<<asystem("pause");}

  除此而外,stringstream類的對象我們還常用它進行string與各種內建類型資料之間的轉換。範例程式碼如下:

#include <iostream>#include <sstream>#include <string>using namespace std;int main(){stringstream sstr;//--------int轉string----------- int a=100;string str;sstr<<a;sstr>>str;cout<<str<<endl;//--------string轉char[]-------- sstr.clear();//如果你想通過使用同一stringstream對象實現多種類型的轉換,請注意在每一次轉換之後都必須調用clear()成員函數。 string name = "colinguan";char cname[200];sstr<<name;sstr>>cname;cout<<cname;system("pause");}

  接下來我們來學習一下輸入/輸出的狀態標誌的相關知識.

5 io_state 輸入/輸出的狀態標誌

C++中負責的輸入/輸出的系統包括了關於每一個輸入/輸出操作的結果的記錄資訊。這些當前的狀態資訊被包含在io_state類型的對象中。io_state是一個枚舉類型(就像open_mode一樣),以下便是它包含的值。

  • goodbit 無錯誤
  • Eofbit 已到達檔案尾
  • failbit 非致命的輸入/輸出錯誤,可挽回
  • badbit 致命的輸入/輸出錯誤,無法挽回

有兩種方法可以獲得輸入/輸出的狀態資訊。一種方法是通過調用rdstate()函數,它將返回目前狀態的錯誤標記。例如,假如沒有任何錯誤,則rdstate()會返回goodbit.下例樣本,表示出了rdstate()的用法:

#include <iostream>using namespace std;int main(){int a;cin>>a;cout<<cin.rdstate()<<endl;if(cin.rdstate() == ios::goodbit){cout<<"輸入資料的類型正確,無錯誤!"<<endl;}if(cin.rdstate() == ios_base::failbit){cout<<"輸入資料類型錯誤,非致命錯誤,可清除輸入緩衝區挽回!"<<endl;}system("pause");}

  另一種方法則是使用下面任何一個函數來檢測相應的輸入/輸出狀態:

bool bad();bool eof();bool fail();bool good();

  下例樣本,表示出了上面各成員函數的用法:

#include <iostream>using namespace std;int main(){int a;cin>>a;cout<<cin.rdstate()<<endl;if(cin.good()){cout<<"輸入資料的類型正確,無錯誤!"<<endl;}if(cin.fail()){cout<<"輸入資料類型錯誤,非致命錯誤,可清除輸入緩衝區挽回!"<<endl;}system("pause");}

  如果錯誤發生,那麼流狀態既被標記為錯誤,你必須清除這些錯誤狀態,以使你的程式能正確適當地繼續運行。要清除錯誤狀態,需使用clear()函數。此函數帶一個參數,它是你將要設為目前狀態的標誌值。,只要將ios::goodbit作為實參。

  範例程式碼如下:

#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");}

通常當我們發現輸入有錯又需要改正的時候,使用clear()變更標記為正確後,同時也需要使用get()成員函數清除輸入緩衝區,以達到重複輸入的目的。

  範例程式碼如下:

#include <iostream>using namespace std;int main(){int a;while(1){cin>>a;if(!cin)//條件可改寫為cin.fail() {cout<<"輸入有錯!請重新輸入"<<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<<"檔案內容已經全部讀完"<<endl;}while(myfile.get(ch)){cout<<ch;}}system("pause");
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.