c++的輸入輸出不是建立在語言上的,而是由iostream
和fstream
文件中定義的一組模板類實(shí)現(xiàn)的,且這個類庫不是正式語言定義的組成部分,就是說cin,cout
等并不是語言的關(guān)鍵字.
流和緩沖區(qū)
c++把輸入輸出看作是字節(jié)流,輸入時,程序從輸入流中截取(>>)字符,輸出時,程序?qū)⒆止?jié)插入(<<)到輸出流.通過這樣的方式,流就相當(dāng)于連接輸入端和輸出端的一個橋梁,兩端只需要關(guān)聯(lián)到相應(yīng)的流上即可實(shí)現(xiàn)連接,這樣處理輸入輸出的方式將獨(dú)立與流的去向.
如下圖所示:
緩沖區(qū)
是指用作中介的內(nèi)存塊,主要作用是用來提高處理輸入輸出的效率.原因在于像磁盤驅(qū)動器這樣的設(shè)備通常是以512字節(jié)的塊為單位來傳輸信息,而程序每次只能處理一個字節(jié).所以通過緩沖的方法,一次從磁盤讀取大量的信息存儲到緩沖區(qū),程序再從緩沖區(qū)中每次讀取一個字節(jié),因?yàn)閺膬?nèi)存中讀取一個字節(jié)的時間要遠(yuǎn)小于從磁盤讀取的時間.
c++I/O文件
各個I/O類的繼承關(guān)系如下圖所示:
ios_basic
類表示流的一般特性,如是否可讀取,是二進(jìn)制流還是文本流.以及獨(dú)立于類型的一些特性.
-
streambuf
類為緩沖區(qū)提供內(nèi)存并提供了用于填充緩沖區(qū),訪問緩沖區(qū)內(nèi)容,刷新緩沖區(qū),管理緩沖區(qū)等的方法 -
ios
類繼承與ios_basic
類并且包含了一個指向streambuf
的指針成員. -
ostream
類繼承自ios
類并提供了輸出方法 -
istream
類繼承自ios
類并提供了輸入方法 -
iostream
類多繼承于istream
和ostream
類
在程序中包含iostream
文件將自動創(chuàng)建8個流對象,4個窄字符流,4個寬字符流:
cin
默認(rèn)關(guān)聯(lián)標(biāo)準(zhǔn)輸入設(shè)備,wcin
與此類似,用于處理wchar_t
類型
-
cout
默認(rèn)關(guān)聯(lián)到標(biāo)準(zhǔn)輸出設(shè)備,wcout
與此類似,用于處理wchar_t
類型 -
cerr
對應(yīng)標(biāo)準(zhǔn)錯誤流,默認(rèn)關(guān)聯(lián)到標(biāo)準(zhǔn)輸出設(shè)備,這個流沒有緩沖機(jī)制,wcerr
.... -
clog
也對應(yīng)標(biāo)準(zhǔn)錯誤流,但是這個流有緩沖機(jī)制,wclog
....
如上所知,c++的以上幾個對象就代表了c++的輸入輸出流.所以在流對象中就包含了與輸入輸出有關(guān)信息的數(shù)據(jù)成員,如顯示數(shù)據(jù)時使用的字段寬度,小數(shù)位數(shù)等...
重定向
由上面流的概述可知流只是充當(dāng)連接輸入端和輸出端的一個橋梁而已.所以我們就可以通過改變流的流向來實(shí)現(xiàn)輸入輸出的重定向功能.
- 標(biāo)準(zhǔn)輸入重定向
<
- 標(biāo)準(zhǔn)輸出重定向
>
- 標(biāo)準(zhǔn)錯誤重定向
2>
假設(shè)我們有一個程序counter從鍵盤接受輸入字符,并返回輸入字符的個數(shù).那么我們只需如下就可以讓counter從文件input.txt中輸入字符,并把結(jié)果存到res.txt中:
counter <input.txt >res.txt
cout進(jìn)行輸出
ios_basic
類中存儲了描述格式狀態(tài)的信息,如計數(shù)系統(tǒng),字段寬度,小數(shù)位數(shù)等,并提供了控制符來控制顯示整數(shù)時的計數(shù)系統(tǒng),由于ios_basic
類是ostream
類的間接基類,所以可在ostream
類的對象中直接使用.例如,要控制整數(shù)以十進(jìn)制,十六進(jìn)制,八進(jìn)制顯示可分別使用dec,hex,oct
控制符.
hex(cout); // 控制符不是成員函數(shù),不必通過對象調(diào)用
進(jìn)行如上設(shè)置后,cout將以十六進(jìn)制顯示,直到將格式設(shè)置為其他選項(xiàng)為止.因?yàn)?code>ostream重載了<<
,所以一般以cout<<hex;
方式單獨(dú)使用控制符.
ps: 對于cin,以上控制符也是可用的,表示以什么進(jìn)制解釋輸入的整數(shù)
字段寬度
使用成員函數(shù)width()
可實(shí)現(xiàn)將長度不同的數(shù)字放到寬度相同的字段中.原型為:
int width(); // 返回字段寬度的當(dāng)前設(shè)置
int width(int i); // 將字段寬度設(shè)置為i并返回設(shè)置之前的字段寬度
注意: width()函數(shù)只影響接下來的一個項(xiàng)目,之后字段將恢復(fù)到默認(rèn)值
填充字符
默認(rèn)的cout使用空格填充字段中未被使用的部分,可使用成員函數(shù)fill(char)
可改變填充字符.與字段寬度設(shè)置不同的是它會一直有效直到更改為止.
設(shè)置浮點(diǎn)數(shù)顯示精度
已知c++默認(rèn)精度是6位,但末尾的0不顯示.可以使用成員函數(shù)precision(int)
來設(shè)置顯示的精度,也就是數(shù)據(jù)的總位數(shù).與fill()
類似,一旦設(shè)置就一直有效直到被更改.
有時輸出需要顯示末尾的0和小數(shù)點(diǎn),ostream
類本身沒有提供這方面的函數(shù),它的基類ios_basic
類提供的成員函數(shù)setf()
可以實(shí)現(xiàn)控制多種格式化特性,
使用setf()
函數(shù)需要進(jìn)行很多設(shè)置,用到很多的ios_basic
的類級靜態(tài)常量,不是很友好.c++在頭文件iomanip
中提供了其他一些控制符可以更方面的實(shí)現(xiàn)格式化特性.如下給出三個最常用的控制符:
- setpricision(int): 設(shè)置精度
- setfill(char): 設(shè)置填充字符
- setw(int): 設(shè)置字段寬度
舉例如下:
#include<cmath>
#include<iomanip>
#include<iostream>
int main()
{
std::cout << std::fixed << std::right; // 顯示m末尾的0; 右對齊
std::cout << std::setprecision(4); // 設(shè)置顯示精度,一直有效
std::cout << std::setw(6) << "N" << std::setw(15) << "squre root" << std::setw(15) << "fourth root" << std::endl;
for (int i=10; i<=100; i+=10)
{
// 設(shè)置字段寬度(只對下一條輸出內(nèi)容有效)和填充字符(一直有效)
std::cout << std::setw(4) << std::setfill('.') << i
<< std::setw(15) << std::setfill(' ') << sqrt(i) << std::setw(15) << sqrt(sqrt(i)) << std::endl;
}
return 0;
}
//下面為輸出
N squre root fourth root
..10 3.1623 1.7783
..20 4.4721 2.1147
..30 5.4772 2.3403
..40 6.3246 2.5149
..50 7.0711 2.6591
..60 7.7460 2.7832
..70 8.3666 2.8925
..80 8.9443 2.9907
..90 9.4868 3.0801
.100 10.0000 3.1623
cin進(jìn)行輸入
cin
可自動識別輸入的數(shù)據(jù)類型,也就是說,它讀取從非空白符開始到與目標(biāo)類型不匹配的第一個字符之間的所有內(nèi)容.剩下不匹配的內(nèi)容(如果還有的話)將留在輸入流中等待下一個cin
語句讀取.如果輸入與預(yù)期不匹配時,那么cin操作的對象將不會被改變并返回狀態(tài)0.可用來檢查輸入是否合法.
單字符輸入
- get(char&)和get() 提供不跳過空白符的單字符輸入功能
- get(char,int,char)和getline(char,int,char)在默認(rèn)情況下讀取整行而不是一個單詞.
在有參數(shù)和沒參數(shù)的情況下,get()
方法都讀取下一個輸入字符,即使是不可見字符.get(char&)將輸入的字符賦給其參數(shù)并返回istream
對像(意味著可拼接,如cin.get(c1).get(c2)),get(void)將輸入的字符轉(zhuǎn)換為整形再返回.如下是兩種方式讀取到文件末尾的寫法:
char ch;
while(cin.get(ch))
{
// process...
}
int ch;
while((ch=cin.get())!=EOF)
{
// process...
}
字符串輸入
成員函數(shù)getline(),get()
都有讀取字符串的版本,他們的特征標(biāo)都相同:
- istream& get(char*,int,char);
- istream& get(char*,int);
- istream& getline(char*,int,char);
- istream& getline(char*,int);
- istream& ignore(int,char);//int表示讀取最大字符數(shù),char表示分界符
第一次參數(shù)表示輸入字符串的內(nèi)存單元地址,第二個參數(shù)表示讀取的最大字符數(shù)(通常要加1用于存儲字符串結(jié)尾字符),第三個參數(shù)表示用于分界的字符串,也就是用于指定停止輸入的字符.要是沒有第三個參數(shù)則默認(rèn)用換行符用作分界符.
上面get和getline的功能都是一樣的,只有一點(diǎn)區(qū)別,get會將分解符留在輸入流中,而getline則讀取分解符并丟棄掉.
其中ignore(int,char)
用于讀取指定數(shù)目的字符或者直到分界符為止,并把讀取到的字符串丟棄.