iostreams 以四個狀態旗標追蹤流物件健康狀態。本文系統整理旗標含義、查詢函式、清除機制與實戰錯誤處理模式。
| 旗標 | 含義 | 觸發情境 | 可恢復性 |
|---|---|---|---|
goodbit | 無錯誤(值為 0) | 所有操作成功 | 正常狀態 |
eofbit | 抵達檔案結尾 | 讀取操作遇到 EOF | 不可恢復(需重開檔案) |
failbit | 邏輯錯誤/格式不符 | 型別不匹配(如讀 int 遇到 "abc")、寬度限制 | **可恢復**(清除旗標+清空緩衝區) |
badbit | 系統級/不可恢復錯誤 | 硬碟故障、記憶體不足、緩衝區損毀 | 不可恢復 |
bool good() const; // rdstate() == goodbit(最常用)
bool eof() const; // rdstate() & eofbit
bool fail() const; // rdstate() & (failbit | badbit)
bool bad() const; // rdstate() & badbit
注意:fail() 包含 badbit,good() 僅在完全無錯誤時為 true。
iostate rdstate() const; // 讀取完整旗標組合
void clear(iostate state = goodbit); // 設定旗標(預設清除所有)
void setstate(iostate state); // 新增旗標(等同 rdstate() | state)
void exceptions(iostate except_mask); // 設定觸發異常的旗標
std::ifstream fin("data.txt");
int value;
while (fin >> value) { // operator>> 回傳 stream&,隱性轉換為 bool 呼叫 good()
process(value);
}
if (fin.eof()) {
std::cout << "正常讀完檔案" << std::endl;
} else if (fin.fail()) {
std::cout << "格式錯誤,清除並嘗試恢復" << std::endl;
fin.clear(); // 清除 failbit
fin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 跳過壞行
// 可繼續後續讀取
} else if (fin.bad()) {
std::cerr << "嚴重 I/O 錯誤" << std::endl;
}
std::ifstream fin("data.txt");
fin.exceptions(std::ifstream::failbit | std::ifstream::badbit); // eofbit 不拋出
try {
int a, b;
fin >> a >> b;
// 任何 fail/bad 直接拋出 ios_base::failure
} catch (const std::ios_base::failure& e) {
std::cerr << "I/O 異常: " << e.what() << std::endl;
}
std::istream& safe_read_int(std::istream& is, int& out) {
if (is >> out) return is; // 成功
if (is.fail()) { // 格式錯誤
is.clear(); // 必須先清除旗標
is.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 丟棄該行
}
// badbit/eofbit 不處理,讓上層決定
return is;
}
// 手動檢查特定旗標
if (fin.rdstate() & std::ios::eofbit) { ... }
// 組合旗標
std::ios::iostate err = std::ios::failbit | std::ios::badbit;
if (fin.rdstate() & err) { ... }
while (!fin.eof()) **錯誤**:EOF 旗標在讀取**失敗後**才設定,會多執行一次迴圈。fin.clear() 不會移動檔案指標,僅重設旗標;需搭配 seekg 重新定位。operator bool()(舊標準 operator void*())回傳 !fail(),即 good() || eofbit。badbit。