1. std::ostream
是什么?
- 定義:
std::ostream
是 C++ 標準庫中的輸出流類,負責將數據輸出到各種目標(如屏幕、文件、網絡等)。 - 你可以把
std::ostream
想象成一根“數據水管”:- 數據從 C++ 代碼流進
std::ostream
(比如std::cout
)。 std::ostream
負責把數據送到 終端、文件或者其他地方。
- 數據從 C++ 代碼流進
- “o” 表示 “output”(輸出)。
- 特點:
- 不能單獨使用,必須依賴一個流緩沖區(
std::streambuf
)。 - 常見的實例:
std::cout
(輸出到控制臺)。
- 不能單獨使用,必須依賴一個流緩沖區(
比喻:std::ostream
就像一根“數據水管”,數據從程序流進去,最終送到屏幕或文件。
示例:
std::cout << "Hello, World!" << std::endl; // 輸出到屏幕
2. 為什么不能直接創建 std::ostream
?
std::ostream os; // ? 錯誤!沒有默認構造函數
- 原因:
std::ostream
需要一個std::streambuf
來管理數據緩沖,但它本身不提供默認緩沖區。 - 解決辦法:用現有的流(如
std::cout
)或手動關聯緩沖區。
正確用法:
std::filebuf buff;
buff.open("a.txt", std::ios::out);
std::ostream os(&buff); // 關聯文件緩沖區
os << "Hello, File!" << std::endl;
3. C++ 中的“流”是什么?
- 流(Stream):數據的抽象化處理方式,像水流一樣從一端流向另一端。
- 輸入流(
std::istream
):外部(如鍵盤、文件) → 程序。 - 輸出流(
std::ostream
):程序 → 外部(如屏幕、文件)。
- 輸入流(
4. I/O 流家族一覽
C++ 的 I/O 流類分布在幾個頭文件中:
頭文件 | 類 | 作用 | 繼承關系 |
---|---|---|---|
<iostream> | std::istream | 輸入流(如 std::cin ) | 繼承 std::ios |
std::ostream | 輸出流(如 std::cout ) | 繼承 std::ios | |
std::iostream | 輸入+輸出流 | 繼承 std::istream 和 std::ostream | |
<fstream> | std::ifstream | 文件輸入 | 繼承 std::istream |
std::ofstream | 文件輸出 | 繼承 std::ostream | |
std::fstream | 文件輸入+輸出 | 繼承 std::iostream | |
<sstream> | std::istringstream | 從字符串解析數據 | 繼承 std::istream |
std::ostringstream | 將數據寫入字符串 | 繼承 std::ostream | |
std::stringstream | 字符串讀+寫 | 繼承 std::iostream |
5. 常見用法與代碼示例
5.1 標準輸入輸出(<iostream>
)
std::cout
輸出:
std::cout << "Hello, World!" << std::endl; // 輸出到屏幕
std::cin
輸入:
int x;
std::cout << "請輸入一個數字: ";
std::cin >> x;
std::cout << "你輸入的是: " << x << std::endl;
- 讀取整行:
std::string name;
std::cout << "請輸入全名: ";
std::getline(std::cin, name); // 支持空格
std::cout << "你好, " << name << "!" << std::endl;
- 錯誤和日志:
std::cerr << "錯誤: 文件未找到!" << std::endl; // 無緩沖,立即輸出
std::clog << "日志: 程序啟動..." << std::endl; // 有緩沖
代碼示例:
#include <iostream>
#include <fstream>int main() {std::filebuf buff;buff.open("a.txt", std::ios::out);std::ostream os(&buff);os << "aaa" << std::endl;os << "aaa" << std::endl;// 這里不需要顯式關閉文件,析構時會自動關閉。// 但如果你希望在某個時刻顯式關閉,可以調用 buff.close() 或 os.close()return 0;
}#include <iostream>
#include <fstream>
int main()
{{std::filebuf buff;buff.open("a.txt", std::ios::in);std::iostream os(&buff);std::string line;std::getline(os, line);std::cout << line << std::endl;}{ std::filebuf buff;buff.open("b.txt", std::ios::out);std::iostream is(&buff);is << "xxx" << 1.2 << std::endl;}return 0;
}
- 無需顯式關閉:
std::ostream
和std::filebuf
會在對象析構時自動處理文件關閉。 - 顯式關閉:如果你想要在某個特定時刻手動關閉文件,可以調用
buff.close()
或os.close()
。
不過,在多數情況下,依賴于析構時自動關閉文件是一個更簡單且推薦的做法。
5.2 文件輸入輸出(<fstream>
)
- 寫入文件:
std::ofstream file("test.txt");
if (file.is_open()) {file << "Hello, 文件!" << std::endl;file.close(); // 可選,析構時自動關閉
}
- 讀取文件:
std::ifstream file("test.txt");
if (file.is_open()) {std::string line;while (std::getline(file, line)) {std::cout << line << std::endl;}file.close();
}
- 讀寫結合:
std::filebuf buff;
buff.open("a.txt", std::ios::out);
std::ostream os(&buff);
os << "Hello" << std::endl;
5.3 字符串流(<sstream>
)
- 字符串轉數值:
std::string str = "42";
int num;
std::istringstream iss(str);
iss >> num; // 解析為 42
std::cout << num << std::endl;
- 數值轉字符串:
int num = 100;
std::ostringstream oss;
oss << "數值: " << num;
std::cout << oss.str() << std::endl; // "數值: 100"
- 讀寫混合:
std::stringstream ss;
ss << "Hello " << 42;
std::string word;
while (ss >> word) {std::cout << word << std::endl; // 輸出 "Hello" 和 "42"
}
5.4 格式化輸出(<iomanip>
)
double num = 1234.56789;
std::cout << std::fixed << std::setprecision(2) << num << std::endl; // 1234.57
std::cout << std::setw(10) << std::setfill('*') << 42 << std::endl; // *******42
6. 關鍵點總結
std::ostream
:輸出流的核心,用于將數據送到外部,依賴std::streambuf
。- 流類型:
<iostream>
:標準輸入輸出(cin
、cout
、cerr
)。<fstream>
:文件操作(ifstream
、ofstream
、fstream
)。<sstream>
:字符串處理(istringstream
、ostringstream
、stringstream
)。
- 格式化:用
<iomanip>
控制輸出樣式。 - 自動管理:流對象析構時會自動關閉文件,無需手動清理(但可以顯式關閉)。
💡 C++ 的 I/O 流就像“水管系統”,統一了各種數據處理方式,既靈活又強大!