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