C++ IO 流體系以 streambuf 為底層緩衝區抽象,ios_base 管理格式狀態,basic_ios 提供狀態查詢,basic_istream/ostream/iostream 實現輸入/輸出操作,basic_stringstream/filebuffer 提供具體來源/目標。
// ostream& operator<<(int val); 返回 *this 支援鏈式
std::cout << "Value: " << 42 << " Hex: " << std::hex << 42 << std::endl;
// 等價於:
std::operator<<(std::operator<<(std::cout, "Value: "), 42) ...;
返回引用而非值,避免拷貝並保持同一流對象身份。
char arr[] = "hello";
char* ptr = arr;
std::cout << arr; // 輸出 "hello" (const char* 重載視為 C 風格字符串)
std::cout << ptr; // 輸出 "hello"
std::cout << &arr; // 輸出地址 (const char(*)[6] 匹配 void* 重載)
std::cout << (void*)ptr; // 顯式輸出地址
int nums[] = {1,2,3};
std::cout << nums; // 輸出地址!無 int* 字符串重載,匹配 void*
關鍵規則:只有 char*/const char*/signed char*/unsigned char* 被視為 C 字符串輸出,其他指針均輸出地址。
| 函數 | 行為 | 典型用法 |
|---|---|---|
get() | 讀取單字符,含換行/空白,EOF 返回 Traits::eof() | char ch; while(cin.get(ch)) process(ch); |
get(ch) | 讀取到參數引用,成功返回 *this,失敗設 failbit | char ch; while(cin.get(ch)) { ... } |
get(buf, n, delim) | 讀最多 n-1 字符至緩衝區,遇 delim 停留流中 | cin.get(buf, 100, '\n'); |
getline(buf, n, delim) | 同上但提取並丟棄 delim | cin.getline(buf, 100); |
read(buf, n) | 讀取固定 n 字節(二進制),不足設 failbit|eofbit | cin.read(buf, sizeof(header)); |
ignore(n, delim) | 跳過最多 n 字符,遇 delim 停止並提取 | cin.ignore(std::numeric_limits<streamsize>::max(), '\n'); |
peek() | 查看下一字符不提取 | if (cin.peek() == '#') skipComment(); |
putback(ch) | 將字符放回流(僅保證 1 字符) | cin.putback(ch); |
// 基數
std::cout << std::hex << 255 << ' ' << std::oct << 255 << ' ' << std::dec << 255; // ff 377 255
// 浮點精度
std::cout << std::fixed << std::setprecision(2) << 3.14159; // 3.14
std::cout << std::scientific << std::setprecision(3) << 1234.5; // 1.235e+03
// 寬度、填充、對齊
std::cout << std::setw(10) << std::setfill('*') << std::left << "text"; // text******
// 布爾值輸出 true/false
std::cout << std::boolalpha << true << ' ' << false; // true false
// 顯示正號、大寫十六進制
std::cout << std::showpos << std::uppercase << std::hex << 255; // +FF
// 狀態位
std::ios::goodbit // 0,一切正常
std::ios::eofbit // 到達文件末尾
std::ios::failbit // 邏輯錯誤(如格式不匹配)
std::ios::badbit // 系統級錯誤(硬件故障)
// 檢查方法
if (cin) { ... } // good()
if (!cin) { ... } // fail() || bad()
if (cin.eof()) { ... } // 專檢 EOF
if (cin.fail()) { ... } // failbit 或 badbit
if (cin.bad()) { ... } // 僅 badbit
// 恢復
cin.clear(); // 清除所有錯誤位
cin.clear(ios::goodbit); // 同明確
cin.setstate(ios::failbit); // 手動設錯誤位
// 同步緩衝區 (C++11 廢棄 sync_with_stdio 相關)
cin.sync(); // 嘗試同步輸入緩衝區與外部設備,行為實現定義
#include <fstream>
// 輸出文件流
std::ofstream ofs("data.txt", std::ios::out | std::ios::trunc);
ofs << "Line 1\n" << 42 << ' ' << 3.14 << std::endl;
ofs.close(); // RAII 析構自動關閉
// 輸入文件流
std::ifstream ifs("data.txt");
std::string line;
while (std::getline(ifs, line)) {
std::cout << line << '\n';
}
// 二進制讀寫
struct Header { int id; double timestamp; };
Header h{1, 1234567890.123};
std::ofstream bin("data.bin", std::ios::binary);
bin.write(reinterpret_cast<const char*>(&h), sizeof(h));
bin.close();
std::ifstream binIn("data.bin", std::ios::binary);
Header h2;
binIn.read(reinterpret_cast<char*>(&h2), sizeof(h2));
int main(int argc, char* argv[]) {
if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " [file2...]\n";
return 1;
}
for (int i = 1; i < argc; ++i) {
std::ifstream fin(argv[i]);
if (!fin) {
std::cerr << "Cannot open: " << argv[i] << '\n';
continue; // 或 return
}
std::cout << "=== " << argv[i] << " ===\n";
std::string line;
while (std::getline(fin, line)) std::cout << line << '\n';
fin.close();
fin.clear(); // 清除狀態供下次復用(若復用同一流對象)
}
}
class Point { int x_, y_;
public:
friend std::ostream& operator<<(std::ostream& os, const Point& p) {
return os << '(' << p.x_ << ", " << p.y_ << ')';
}
friend std::istream& operator>>(std::istream& is, Point& p) {
char c; return is >> c >> p.x_ >> c >> p.y_ >> c; // 解析 (x, y)
}
};
std::ostream& timestamp(std::ostream& os) {
auto now = std::chrono::system_clock::now();
auto t = std::chrono::system_clock::to_time_t(now);
return os << '[' << std::put_time(std::localtime(&t), "%F %T") << "] ";
}
// 使用
std::cout << timestamp << "Log message\n"; // [2024-01-15 14:30:00] Log message
std::ios::sync_with_stdio(false); std::cin.tie(nullptr); 關閉 C/C++ 流同步與 cin/cout 綁定,大幅提速。ostringstream 累積一次性 flush,或直接寫入文件流。read/write 避免格式化開銷。std::endl(隱含 flush),改用 '\n'。C++ IO 流雖語法豐富、類型安全、可擴展,但需注意:
<format> (C++20)、<filesystem>、span 進一步簡化代碼。