流類簡介
C++中凡是數(shù)據(jù)從一個(gè)地方傳輸?shù)搅硪粋€(gè)地方的操作都是流的操作。因此,一般意義下的讀操作在流數(shù)據(jù)抽象中被稱為(從流中)“提取”,寫操作被稱為(向流中)“插入”。
iostream流類庫的類關(guān)系圖如下:

圖中箭頭代表派生關(guān)系。ios是抽象基類,提供輸入/輸出所需的公共操作,它派生出兩個(gè)類istream和ostream。為了避免多重繼承的二義性,從ios派生istream和ostream時(shí),均使用了virtual關(guān)鍵字(虛繼承)。
stream類提供了流的大部分輸入操作,對系統(tǒng)預(yù)定義的所有輸入流重載提取運(yùn)算符>>。ostream類對系統(tǒng)預(yù)定義的所有輸出流重載插入運(yùn)算符<<。
C++的iostream類庫提供了數(shù)百種I/O功能,iostream類庫的接口部分包含在幾個(gè)頭文件中。常見的頭文件有以下3個(gè):
-
iostream:包含操作所有輸入/輸出流所需要的基本信息,因此大多數(shù)C++程序都應(yīng)包含這個(gè)頭文件。該文件含有4個(gè)標(biāo)準(zhǔn)流對象,提供了無格式化和格式化的I/O功能。 -
iomanip:包含格式化I/O的帶參數(shù)流操縱符,可用于指定數(shù)據(jù)輸入/輸出的格式。 -
fstream:包含處理文件的有關(guān)信息,提供建立文件、讀/寫文件的各種操作接口。
標(biāo)準(zhǔn)流對象
C++在頭文件iostream中為了用戶預(yù)定義了4個(gè)標(biāo)準(zhǔn)流對象,分別是:
-
cin(標(biāo)準(zhǔn)輸入流),cin與標(biāo)準(zhǔn)輸入設(shè)備(鍵盤)相關(guān)聯(lián),用于讀取數(shù)據(jù),可以被重定向?yàn)閺奈募凶x取數(shù)據(jù)。 -
cout(標(biāo)準(zhǔn)輸出流),cout與標(biāo)準(zhǔn)輸出設(shè)備(顯示器)相關(guān)聯(lián),用于輸出數(shù)據(jù),可以被重定向?yàn)橄蛭募飳懭霐?shù)據(jù)。 -
cerr(非緩沖錯(cuò)誤輸出流),cerr與標(biāo)準(zhǔn)錯(cuò)誤信息輸出設(shè)備(顯示器)相關(guān)聯(lián)(非緩沖),用于輸出出錯(cuò)信息,不能被重定向。 -
clog(緩沖錯(cuò)誤輸出流),clog與標(biāo)準(zhǔn)錯(cuò)誤信息輸出設(shè)備相關(guān)聯(lián)(緩沖),用于輸出出錯(cuò)信息,不能被重定向。
在實(shí)際中,cin常用于從鍵盤輸入數(shù)據(jù),是流類istream的對象。cout常用于向屏幕輸出數(shù)據(jù),是流類ostream的對象。
#include <iostream>
using namespace std;
int main() {
int x, y;
cin >> x >> y;
//函數(shù)`freopen()`的功能是將`stream`按`mode`指定的模式重定向到路徑`path`指向的文件。
//將標(biāo)準(zhǔn)輸出定向到文件test.txt
freopen("test.txt", "w", stdout);
if (y == 0) {
cerr << "error" << endl;
} else {
cout << x << " / " << y << " = " << x / y << endl;
}
return 0;
};
控制I/O格式
C++進(jìn)行I/O格式控制的方式一般有使用流操縱符、設(shè)置標(biāo)志字和調(diào)用成員函數(shù)。
流操縱符
| 流操縱符 | 作用 |
|---|---|
| endl | 輸出一個(gè)新行符,并清空流 |
| ends | 輸出字符串結(jié)束,并清空流 |
| flush | 清空流緩沖區(qū) |
| dec*(默認(rèn)) | 以十進(jìn)制形式輸入/輸出整數(shù) |
| hex | 以十六進(jìn)制形式輸入或輸出整數(shù) |
| cot | 以八進(jìn)制形式輸入或輸出整數(shù) |
| ws | 提取空白字符 |
| fixed | 以普通小數(shù)形式輸出浮點(diǎn)數(shù) |
| scientific | 以科學(xué)計(jì)數(shù)法形式輸出浮點(diǎn)數(shù) |
| left | 左對齊,即在寬度不足時(shí)將填充字符添加到右邊 |
| right* | 右對齊,即在寬度不足時(shí)將填充字符添加到左邊 |
| setbase(int b) | 設(shè)置輸出整數(shù)時(shí)的進(jìn)制,b為8、10、16 |
| setw(int w) | 指定輸出寬度為w個(gè)字符,或輸入字符串時(shí)讀入w個(gè)字符。 一次有效。 |
| setfill(int c) | 在指定輸出寬度的情況下, 輸出的寬度不足時(shí)用 ASCⅡ碼為c的字符填充(默認(rèn)情況是用空格填充) |
| setprecision(int n) | 設(shè)置輸出浮點(diǎn)數(shù)的精度為n。在使用非 fixed且非scientific方式輸出的情況下,n即為有效數(shù)字最多的位數(shù)。如果有效數(shù)字位數(shù)超過 n,則小數(shù)部分四舍五入, 或自動變?yōu)榭茖W(xué)計(jì)數(shù)法輸出并保留一共 n位有效數(shù)字;在使用 fixed方式和scientific方式輸出的情況下,n是小數(shù)點(diǎn)后面應(yīng)保留的位數(shù)。 |
| setiosflags(fmtflags f) | 通用操縱符。將格式標(biāo)志f所對應(yīng)的格式標(biāo)志位置為1
|
| resetiosflags(fmtflags f) | 通用操縱符。將格式標(biāo)志f所對應(yīng)的格式標(biāo)志位置為0(清除) |
| boolapha | 把ture和false輸出為字符串 |
| noboolapha* | 把ture和false輸出為1和0
|
| showbase | 輸出表示數(shù)值進(jìn)制的前綴 |
| noshowbase* | 不輸出表示數(shù)值進(jìn)制的前綴 |
| showpoint | 總是輸出小數(shù)點(diǎn) |
| noshowpoint* | 只有當(dāng)小數(shù)部分存在時(shí)才顯示小數(shù)點(diǎn) |
| showpos | 在非負(fù)數(shù)值中顯示+
|
| noshowpos* | 在非負(fù)數(shù)值中不顯示+
|
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
int n = 65535, m = 20;
//1.分別輸出一個(gè)整數(shù)的十進(jìn)制、十六進(jìn)制和八進(jìn)制表示
cout << "1)" << n << " = " << hex << n << " = " << oct << n << endl;
//1)65535 = ffff = 177777
//2.使用setbase分別輸出一個(gè)整數(shù)的十進(jìn)制、十六進(jìn)制和八進(jìn)制表示
cout << "2)" << setbase(10) << m << " = " << setbase(16) << m << " = " << setbase(8) << m << endl;
//2)20 = 14 = 24
//3.使用showbase和setbase分別輸出一個(gè)整數(shù)的十進(jìn)制、十六進(jìn)制和八進(jìn)制表示
cout << "3)" << showbase;//輸出表示數(shù)值進(jìn)制的前綴
cout << setbase(10) << m << " = " << setbase(16) << m << " = " << setbase(8) << m << endl;
//3)20 = 0x14 = 024
return 0;
};
標(biāo)志字
| 標(biāo)志常量名 | 值 | 含義 | 輸入/輸出 |
|---|---|---|---|
| ios::skipws | 0x0001 | 跳過輸入中的空白 | I |
| ios::left | 0x0002 | 按輸出域左對齊,用填充字符填充右邊 | O |
| ios::right* | 0x0004 | 按輸入域右對齊,用填充字符填充做左邊 | O |
| ios::internal | 0x0008 | 在符號位或基數(shù)指示符后填入字符 | O |
| ios::dec* | 0x0010 | 轉(zhuǎn)換為十進(jìn)制基數(shù)形式 | I/O |
| ios::oct | 0x0020 | 轉(zhuǎn)換為八進(jìn)制基數(shù)形式 | I/O |
| ios::hex | 0x0040 | 轉(zhuǎn)換為十六進(jìn)制基數(shù)形式 | I/O |
| ios::showbase | 0x0080 | 在輸出中顯示基數(shù)指示符 | O |
| ios::showpoint | 0x0100 | 在輸出浮點(diǎn)數(shù)時(shí)必須帶小數(shù)點(diǎn)和尾部的0
|
O |
| ios::uppercase | 0x0200 | 以大寫字母表示十六進(jìn)制數(shù),科學(xué)計(jì)數(shù)法使用大寫字母 | O |
| ios::showpos | 0x0400 | 正數(shù)前面加+號 |
O |
| ios::scientific | 0x0800 | 科學(xué)計(jì)數(shù)法顯示浮點(diǎn)數(shù) | O |
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
double x = 12.34;
cout << "1)" << setiosflags(ios::scientific | ios::showpos) << x << endl;
cout << "2)" << setiosflags(ios::fixed) << x << endl;
cout << "3)" << resetiosflags(ios::fixed) << setiosflags(ios::scientific | ios::showpos) << x << end;
cout << "4)" << resetiosflags(ios::showpos) << x << endl;
//1)+1.234000e+001
//2)+12.34
//3)+1.234000e+001
//4)1.234000e+001
return 0;
};
調(diào)用cout的成員函數(shù)
| 成員函數(shù) | 作用相同的流操作符 |
|---|---|
| precision(int np) | setprecision(np) |
| width(int nw) | setw(nw) |
| fill(char cFill) | setfill(cFill) |
| setf(long iFlags) | setiosflags(iFlags) |
| unsetf(long iFlags) | resetiosflags(iFlags) |
#include <iostream>
using namespace std;
int main(){
double values[] = {
1.23,
20.3456,
300.4567,
4000.45678,
50000.1234567
};
cout.fill('*');//設(shè)置填充字符為`*`
for (int i = 0; i < sizeof(values) / sizeof(double); i++) {
cout << "values[" << i << "] = (";
cout.width(10);//設(shè)置輸出寬度
cout << values[i] << ")" << endl;
}
/*
values[0] = (******1.23)
values[1] = (***20.3456)
values[2] = (***300.457)
values[3] = (***4000.46)
values[4] = (***50000.1)
*/
cout.fill(' ');//設(shè)置填充字符為空格
for (int j = 0; j < sizefo(values) / sizeof(double); j++) {
cout << "values[" << j << "] = ("
cout.width(10);//設(shè)置輸出寬度
cout.precision(j + 3);//設(shè)置保留有效數(shù)字
cout << values[j] << ")" << endl;
}
/*
values[0] = ( 1.23)
values[1] = ( 20.35)
values[2] = ( 300.46)
values[3] = ( 4000.46)
values[4] = ( 50000.12)
*/
return 0;
};
調(diào)用cin的成員函數(shù)
istream類提供了一些公有成員函數(shù),它們可以以不同的方式提取輸入流中的數(shù)據(jù)。
get()函數(shù)
#include <iostream>
using namespace std;
int main() {
int n = 0;
char ch;
//當(dāng)文件沒有結(jié)束時(shí)繼續(xù)進(jìn)行循環(huán)
while ((ch = cin.get()) != EOF) {
cout.put(ch);
n++;
}
cout << "輸入字符共計(jì):" << n << endl;
};
在Windows環(huán)境下,當(dāng)進(jìn)行鍵盤輸入時(shí),在單獨(dú)的一行按ctrl + z組合鍵后再按enter鍵就代表文件輸入結(jié)束。
getline()函數(shù)
getline()成員函數(shù)的原型如下:
istream & getline(char *buf, int bufSize);
其功能是從輸入流中的當(dāng)前字符開始讀取bufSize - 1個(gè)字符到緩沖區(qū)buf,或讀到\n為止(哪個(gè)條件先滿足即按哪個(gè)執(zhí)行)。函數(shù)會在buf中讀入數(shù)據(jù)的結(jié)尾自動添加串結(jié)束標(biāo)記\0。
istream & getline(char *buf, int bufSize, char delim);
其功能是從輸入流中的當(dāng)前字符開始讀取bufSize - 1個(gè)字符到緩沖區(qū)buf,或讀到字符delim為止(哪個(gè)條件先滿足即按哪個(gè)執(zhí)行)。函數(shù)會在buf中讀入數(shù)據(jù)的結(jié)尾自動添加\0。
兩者的區(qū)別在于,前者是讀到\n為止,后者是讀到指定字符delim為止。字符\n或delim都不會被存入buf中,但會從輸入流中取走。
函數(shù)getline()的返回值是函數(shù)所作用的對象的引用。如果輸入流中\n或delim之前的字符個(gè)數(shù)達(dá)到或超過bufSize,則會導(dǎo)致讀入操作出錯(cuò),其結(jié)果是:雖然本次讀入已經(jīng)完成,但是之后的讀入都會失敗。
#include <iostream>
using namespace std;
int main() {
char buf[10];
int i = 0;
//若輸入流的一行超過9個(gè)字符,則會出錯(cuò)
while (cin.getline(buf, 10)) {
cout << ++i << ":" << buf << endl;
}
cout << "last:" << buf << endl;
return 0;
};
eof()函數(shù)
eof()成員函數(shù)的原型如下:
bool eof();
eof()函數(shù)用于判斷輸入流是否已經(jīng)結(jié)束。返回值為true表示輸入結(jié)束。
在應(yīng)用程序中可以用eof()函數(shù)測試是否到達(dá)文件尾,當(dāng)文件操作結(jié)束遇到文件尾時(shí),函數(shù)返回1;否則返回0。
ignore()函數(shù)
ignore()成員函數(shù)的原型如下:
istream & ignore(int n = 1, int delim = EOF);
此函數(shù)的作用是跳過輸入流中的n個(gè)字符,或跳過delim及其之前的所有字符(哪個(gè)條件先滿足就按哪個(gè)執(zhí)行)。兩個(gè)參數(shù)都有默認(rèn)值。因此cin.ignore()等效于cin.ignore(1, EOF),即跳過一個(gè)字符。該函數(shù)常用于跳過輸入中的無用部分,以便提取有用的部分。
#include <iostream>
using namespace std;
int main() {
char str[30];
while (!cin.eof()) {
cin.ignore(10, ':');
if (!cin.eof()) {
cin >> str;
cout << str << endl;
}
}
return 0;
};
peek()函數(shù)
peek()成員函數(shù)的原型如下:
int peek();
函數(shù)peek()返回輸入流中的當(dāng)前字符,但是并不將該字符從輸入流中取走,相當(dāng)于只是“看了一眼”將要讀入的下一個(gè)字符,因此叫“窺視”。
cin.peek()不會跳過輸入流中的空格和回車符。在輸入流已經(jīng)結(jié)束的情況下,cin.peek()返回EOF。