C++ 輸入輸出流:簡單地介紹了【輸入輸出流】、【檔案輸入輸出流】和【字元串輸入輸出流】。
目錄
- STL 輸入輸出流:整體架構
- A) 輸入、輸出流
- 1. 簡介
- 2. 格式化輸出
- 3. 流操縱算子
- 4.
對象的唯一性cout
- B) 檔案輸入、輸出流
- 1. 基本使用方法
- 2. 讀入常用操作
- C) 字元串輸入、輸出流
- 1. 簡介
- 2. 對象内的 buffer
- 3. 實作類型轉換
STL 輸入輸出流:整體架構
頭檔案 | 定義在頭檔案裡的類 / 對象 | 補充說明 |
---|---|---|
| 類、 類 | 類是所有輸入流的基類 |
| 類 | 類是所有輸出流的基類 |
| 對象、 對象 | 是 類的對象; 是 類的對象 |
| 類、 類、 類 | |
| 類、 類、 類 |
回到頂部
A) 輸入、輸出流
***
istream
和
ostream
類似,以下以
ostream
展開說明。
1. 簡介
-
= output streamostream
- 是所有輸出流的基類
- 類内重載了不同基礎資料類型的輸出流運算符,如:
、int
、char
...bool
- 優勢:統一了輸出接口,避免輸出混亂
- STL 中定義了一個
類的對象:ostream
cout
,将資料送到标準輸出流
以下是自定義實作
的方法:ostream
以下是在自定義類中重載流運算符的方法:class ostream { public: ostream& operator<< (int num) { printf("%d", num); return *this; } ostream& operator<< (const char* str) { printf("%s", str); return *this; } ...... // 重載需要輸出的類型 } cout; // 定義 ostream 類的對象 int main() { cout << 21 << "happy" ; // 根據輸出資料類型,調用不同的輸出函數 return 0; }
注意:第二個參數可以是不同形式,不一定是引用,如:class MyClass { public: friend ostream& operator<< (ostream&, MyClass&); ...... } ostream& operator<< (ostream& output, MyClass& x) { output << ... ; return outpur; }
、T
、T&
、const T
const T&
回到頂部
2. 格式化輸出
- 常用的格式化輸出方式有:
#include <iomanip> cout << fixed << 3 << " " << 3.14 << " " << 3.14159265; /* 将小數的小數點固定為 6 位 輸出結果:3 3.140000 3.141593 */ cout << setprecision(3) << 3.1415926 << 0.1054; /* 設定有效數字 輸出結果:3.14 0.105 */ cout << fixed << setprecision(2) << 3.1415; /* fixed 和 setprecision 合用,可以設定小數點數位 輸出結果:3.14 */ cout << setw(5) << 921; /* 設定輸出的寬度,一次隻對一個輸出有效 預設向右對齊 */ for(int i = 8; i <= 12; ++i) { cout << setw(5) << setfill('*') << i; } /* 設定輸出的寬度 + 空白處填滿指定字元 輸出結果:****8****9***10***11***12 */ cout << scientific << 2018.0 << " " << 0.0001; /* 以科學計數形式輸出 輸出結果:2.018000e+03 1.000000e-04 */
- 以上的
、fixed
等,包括實作換行的setprecision()
,都是流操縱算子endl
回到頂部
3. 流操縱算子
- 借助輔助類,設定成員變量的類
- 一些實作方式有在标準中定義,一些沒有,不同編譯器的實作不同
-
實作的示例:setprecision
class setprecision { private: int precision; public: setprecision(int p): precision(p) {} friend class ostream; } class ostream { private: int precision; public: ostream& operator<< (const setprecision &m) { precision = m.precision; return *this; } } cout; cout << setprecision(2); // setprecision(2) 會構造一個 setprecision 類的對象,作為參數傳入輸出流的函數
-
實作的示例:endl
清空緩沖區的好處:減少外部讀寫次數、保證内容正确讀寫到檔案class ostream { ...... ostream& endl(ostream& os) { os.put('\n'); // 輸出換行符 os.flush(); // 清空緩沖區 return os; } ostream& operator<< (ostream& (*fn)(ostream&)) { return (*fn)(*this); } } // 換行方法1:調用輸出流+流操縱算子 cout << endl; // 換行方法2:直接使用endl函數 endl(cout);
回到頂部
4. cout
對象的唯一性
cout
- 定義重載流運算符 / 使用
的方式:cout
- 所有重載流運算符都會傳回引用
ostream&
-
類的拷貝構造函數會手動進行删除ostream
ostream(const ostream& x) = delete; ostream(ostream&& x);
- 所有重載流運算符都會傳回引用
- 原因:
- 減少複制開銷
- 隻移動不複制,隻使用一個全局對象
進行輸出cout
- 多個對象無法同步輸出狀态
回到頂部
B) 檔案輸入、輸出流
類 | 名 | 功能 | 補充說明 |
---|---|---|---|
| 檔案輸入流 | 從檔案中讀取資料 | 是 的子類 在編譯期間已經解析完畢 性能較好,取代了 ( 是有寫入非法記憶體的風險) |
| 檔案輸出流 | 将資料寫入檔案中 | 是 的子類 |
***
ifstream
和
ofstream
類似,以下以
ifstream
進行說明:
回到頂部
1. 基本使用方法
#include <fstream>
#include <iostream>
using namespace std;
int main() {
// 打開普通文本檔案
ifsream input("filename.txt");
// 以二進制形式打開檔案
ifstream input("filename.bin", ifstream::binary);
// 確定檔案正确打開才進行操作
if(input) {
...
}
// 操作完畢,關閉檔案
input.close();
return 0;
}
回到頂部
2. 讀入常用操作
- 判斷是否到了文末
while(input) { ... }
- 去除前導空格
input >> ws;
- 檢查下一個字元,如果到了文末就停止
int c = input.peek(); if(c == EOF) break;
- 讀取
int n; input >> n; string str; input >> str; getline(cin, str); ... char sentence[1000]; input.getline(sentence, 1000);
回到頂部
C) 字元串輸入、輸出流
1. 簡介
-
stringstream
- 是
的子類iostream
- 在對象内維護一個 buffer,可以實作輸入和輸出
- 流輸出函數:将資料寫入 buffer
- 流輸入函數:從 buffer 讀入資料
- 是
- 基本使用方法
#include <sstream> using namespace std; int main() { stringstream ss; ss << "10"; // 将資料寫進 ss 的 buffer ss << "0 200"; // 會自動連接配接字元串 int a, b; ss >> a >> b; // 從 buffer 讀取資料,轉換成 int return 0; }
回到頂部
2. 對象内的 buffer
- 暫存資料的空間,包含已讀取和未讀取的内容
- 可以用
來傳回 buffer 内的内容(傳回類型:string)ss.str()
stringstream ss; ss << "10"; // buffer内有【10】 ss << "0 200"; // buffer内有【100 200】 int a, b; ss >> a; // a = 100,buffer内有【100 200】 ss >> b; // b = 200,buffer内有【100 200】 ss.str(""); // 清空 buffer
- 從以上代碼可見,buffer 内的内容不會因為被讀取而減少
- 有兩個指針在維護着:head 和 tail
- head:指向最後一個内容(下一個位置就是寫入新内容的位置)
- tail:指向待讀取的第一個元素
- 所有 head 在 tail 的後面,head 和 tail 之間是未讀取的元素
回到頂部
3. 實作類型轉換
template<class outtype, class intype>
outtype convert(intype val) {
static stringstream ss; // 避免重複初始化
ss.str(""); // 清空 buffer
ss.clear(); // 清空狀态位
ss << val;
outtype result; // 定義要轉換的類型的變量
ss >> result;
return result; // 傳回轉換後的内容
}
// 使用
string str = convert<string>(921);
int num = convert<int>("122");
回到頂部