前言
C++ IO 庫分為「基於流的 IO」與「C 風格 IO 函數」兩大體系。本文聚焦現代 C++ 核心——iostream 流庫,深度解析類繼承體系、類型別名、條件狀態機制、緩衝區控制、文件/字符串流實戰,助你構建健壯、高效的 IO 代碼。
一、流類繼承體系與類型別名
1. 核心繼承關係
ios_base (接口層:格式旗標、異常掩碼)
↑
basic_ios (基類:流狀態、緩衝區指針、tie、rdbuf)
↑
basic_streambuf (緩衝區抽象:內存/文件/字符串)
↑
basic_istream / basic_ostream / basic_iostream (輸入/輸出/雙向流)
↑
basic_ifstream / basic_ofstream / basic_fstream (文件流)
basic_istringstream / basic_ostringstream / basic_stringstream (字符串流)
2. 標準類型別名 (<ios>, <streambuf>, <istream>, <ostream>, <fstream>, <sstream>)
| 窄字符 | 寬字符 | 說明 |
ios | wios | basic_ios 別名 |
streambuf | wstreambuf | basic_streambuf 別名 |
filebuf | wfilebuf | basic_filebuf 別名 |
stringbuf | wstringbuf | basic_stringbuf 別名 |
istream | wistream | basic_istream 別名 |
ostream | wostream | basic_ostream 別名 |
iostream | wiostream | basic_iostream 別名 |
ifstream | wifstream | basic_ifstream 別名 |
ofstream | wofstream | basic_ofstream 別名 |
fstream | wfstream | basic_fstream 別名 |
istringstream | wistringstream | basic_istringstream 別名 |
ostringstream | wostringstream | basic_ostringstream 別名 |
stringstream | wstringstream | basic_stringstream 別名 |
3. 預定義標準流對象
cin / wcin:標準輸入流(關聯 stdin)
cout / wcout:標準輸出流(關聯 stdout,默認行緩衝/全緩衝)
cerr / wcerr:標準錯誤流(無緩衝,立即刷新)
clog / wclog:標準日誌流(全緩衝)
可通過 rdbuf() 重定向緩衝區,改變流行為(如將 cout 導向文件)。
二、流條件狀態機制
1. 四大狀態旗標
| 旗標 | 含義 | 對應查詢函數 |
goodbit | 流正常,無錯誤 | good() |
eofbit | 到達文件/流末尾 | eof() |
failbit | 操作失敗(如格式錯誤),可恢復 | fail() |
badbit | 流損壞(如硬件故障),不可恢復 | bad() |
2. 狀態操作函數
rdstate() // 獲取當前狀態位掩碼
setstate(flags) // 設置狀態位(或運算)
clear(flags=goodbit) // 重置狀態,默認清除所有錯誤位
exceptions(mask) // 設置哪些狀態位觸發異常拋出
3. 實戰:狀態控制與錯誤恢復
#include
#include
#include
using namespace std;
int main() {
string obj = "just a test!";
stringstream ss(obj);
// 手動設置 failbit 模拟錯誤
auto state = ss.rdstate();
ss.setstate(state | stringstream::failbit);
string tmp;
while (ss >> tmp) { // 因 failbit 設置,循環不會執行
cout << tmp << endl;
}
cout << "fail() = " << ss.fail() << endl; // 1 (true)
// 恢復流狀態
ss.clear(); // 清除所有錯誤位
ss.seekg(0); // 重置讀取位置
while (ss >> tmp) {
cout << tmp << endl; // 正常輸出: just / a / test!
}
return 0;
}
4. 狀態位與查詢函數對應表
| 查詢函數 | 返回 true 的條件 |
good() | rdstate() == goodbit |
eof() | (rdstate() & eofbit) != 0 |
fail() | (rdstate() & (failbit | badbit)) != 0 |
bad() | (rdstate() & badbit) != 0 |
三、格式化控制
// 基數
cout << hex << 255 << endl; // ff
cout << dec << 255 << endl; // 255
// 浮點精度與格式
cout << fixed << setprecision(2) << 3.14159 << endl; // 3.14
cout << scientific << 1000.0 << endl; // 1.00e+03
// 寬度、填充、對齊
cout << setw(10) << setfill('*') << left << "hello" << endl; // hello*****
// 布爾值輸出 true/false
cout << boolalpha << true << endl; // true
四、文件流 (<fstream>) 實戰
1. 基本打開模式
| 模式旗標 | 含義 |
ios::in | 讀取 |
ios::out | 寫入(默認截斷文件) |
ios::app | 追加寫入(保留原內容) |
ios::ate | 打開後定位到文件末尾 |
ios::trunc | 截斷文件(默認) |
ios::binary | 二進制模式(無換行符轉換) |
2. 完整讀寫示例
#include
#include
#include
void write_file() {
ofstream ofs("data.txt", ios::out | ios::trunc);
if (!ofs) { cerr << "open failed\n"; return; }
ofs << "Line 1\n" << "Line 2\n";
ofs.close(); // RAII 析構自動關閉,手動 close 可提前檢查錯誤
}
void read_file() {
ifstream ifs("data.txt", ios::in);
if (!ifs) { cerr << "open failed\n"; return; }
string line;
while (getline(ifs, line)) { // 按行讀取,不包含換行符
cout << line << endl;
}
// 二進制讀取
ifstream bin("data.bin", ios::in | ios::binary);
bin.seekg(0, ios::end);
size_t size = bin.tellg();
bin.seekg(0, ios::beg);
vector buffer(size);
bin.read(buffer.data(), size);
}
五、字符串流 (<sstream>) 實戰
#include
#include
#include
void parse_csv_line(const string& line) {
stringstream ss(line);
string field;
vector fields;
while (getline(ss, field, ',')) { // 指定分隔符
fields.push_back(field);
}
// fields 現包含所有欄位
}
string format_output(int id, double score) {
ostringstream oss;
oss << "ID:" << id << " Score:" << fixed << setprecision(1) << score;
return oss.str(); // 獲取格式化字符串
}
六、C 風格 IO (<cstdio>) 互操作
std::ios::sync_with_stdio(false):關閉 C/C++ 流同步,**大幅提升 IO 性能**(競程必開)。
cin.tie(nullptr):解除 cin 與 cout 綁定,進一步加速(無需交互提示時)。
- 混用時注意:關閉同步後,**不能**混用
printf/scanf 與 cout/cin,行為未定義。
七、最佳實踐清單
- 優先使用
iostream,類型安全、可擴展、支援自定義類型重載 operator<</>>。
- 讀取前檢查流狀態:
if (cin >> x) 隱式轉換為 bool 等價於 !cin.fail()。
- 大量數據讀寫:關閉同步
ios::sync_with_stdio(false); cin.tie(nullptr);。
- 文件流利用 RAII,避免手動
close(),析構自動刷新並關閉。
- 二進制數據務必加
ios::binary,避免 Windows 下 \n↔\r\n 轉換損壞數據。
- 異常安全:設置
exceptions(failbit | badbit) 讓流錯誤拋出異常,配合 RAII 實現自動清理。