目錄
????????一、輸入輸出操作
????????????????1. 相關的類
????????????????2. 標準流對象
????????????????3. istream類的成員函數
二、流操縱算子
????????1. 整數流的基數
????????2. 浮點數精度的流操縱算子
????????3. 域寬的流操縱算子
????????4. 其他的流操縱算子
????????5. 用戶自定義流操縱算子
三、文件讀寫
????????1. 文本文件的讀寫
????????2. 二進制文件的讀寫
????????3. 文件讀寫指針
????????4. 文本文件和二進制文件區別
一、輸入輸出操作
1. 相關的類
- ios基類派生出istream和ostream。
- istream派生出ifstream,ostream派生出ofstream。
- iostream繼承自istream和ostream。
- fstream繼承自iostream。
注意:cin就是istream類的對象,cout就是istream類的對象。
2. 標準流對象
(1) 輸入流對象:cin與標準輸入設備相連(從鍵盤獲取數據)。也可以被重定向為從文件中讀取數據。
(2) 輸出流對象:
- cout與標準輸出設備相連(在屏幕上打印數據)。也可以被重定向為向文件寫入數據(freopen函數)。
- cerr與標準錯誤輸出設備相連。
- clog與標準錯誤輸出設備相連。
- cerr和clog的區別在于cerr不使用緩沖區,直接向顯示器輸出信息;而clog采用緩沖區,只有緩沖區滿或者刷新時才會輸出到屏幕上。
(3) 代碼示例:
【1】輸出重定向
#define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std;int main() {double x, y;cin >> x >> y;//freopen函數:輸出重定向到文件//原型:FILE *freopen(const char *path, const char *mode, FILE * stream);//path是目標文件//mode為文件打開模式"r"或"w"//stream為標準流文件,例如stdin標準輸入流, stdout標準輸出流, stderr標準錯誤流freopen("cout.txt", "w", stdout);if (y == 0) {cerr << "error!" << endl;}else {cout << x / y;//輸出到文件cout.txt中}return 0; }
??
顯然,屏幕上并沒有輸出計算結果0.5,該結果輸出到cout.txt文件中。
【2】輸入重定向
#define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std;int main() {int n1 = 0, n2 = 0;//freopen函數:輸入重定向freopen("input.txt", "r", stdin);cin >> n1 >> n2;//由于重定向了,不會在終端等用戶輸入cout << "結果:" << n1 << ", " << n2 << endl;return 0; }
【3】判斷輸入流結束
#define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std;int main() {int x;freopen("test.txt", "r", stdin);while (cin >> x) {cout << "讀入:" << x << endl;}return 0; }
注意:①這里將cin重定向為從文件讀取數據,那么讀到文件末尾即結束。若未重定向,從鍵盤中輸入則需要單獨一行輸入Ctrl+Z代表輸入流結束。②cin >> x返回值為istream&,而istream會有對象的重載,將其轉換成bool類型,因此可以作為循環條件。
3. istream類的成員函數
(1) getline函數:
- 原型:①istream& getline(char* buf, int bufSize); ②istream& getline(char* buf, int bufSize, char delim);
- 對于第一個原型:從輸入流中讀取bufSize-1個字符到緩沖區buf,或讀到'\n'為止(哪個先到算哪個)。
- 對于第二個原型:從輸入流中讀取bufSize-1個字符到緩沖區buf,或讀到delim字符為止(哪個先到算哪個)。
- ?注意:
- 兩個函數都會自動在buf中讀入數據的結尾添加'\0'。
- ‘\0’和delim都不會被讀入buf,但會被輸入流中取走。
- 如果輸入流中'\n'或delim之前的字符個數達到或超過了bufSize個,就導致讀入錯誤,即雖然本次讀入已經完成,但是之后的讀入就都失敗了。
- 可以用if (!cin.getline(...))判斷輸入是否結束。
(2) bool eof(); 用于判斷輸入流是否結束。
(3) int peek(); 返回下一個字符,但不從流中去除。
(4) istream& putback(char c); 將字符ch放回輸入流的頭部。
(5) istream& ignore(int nCount = 1, int delim = EOF); 從流中刪掉最多nCount個字符,遇到EOF結束。
(6) getline函數代碼示例:
#include <iostream>
using namespace std;int main()
{int x;char buf[90];cin >> x;cin.getline(buf, 90, '\n');cout << buf << endl;return 0;
}
二、流操縱算子
1. 整數流的基數
(1) 說明:在cout時,可以指定輸出的整數的進制:dec(十進制)、oct(八進制)、hex(十六進制)。
(2) 注意:①使用流操縱算子,需要添加頭文件iomanip。②一旦設置,就會持續有效直到新的操縱算子出現。
(3) 代碼示例:
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <iomanip> using namespace std;int main() {int n = 10;cout << dec << n << endl;//十進制顯示ncout << oct << n << endl;//八進制顯示ncout << hex << n << endl;//十六進制顯示n//一旦設置dec、oct或者hex,就會持續有效直到寫新操縱算子。cout << n << endl;return 0; }
2. 浮點數精度的流操縱算子
(1) precision:是ostream的成員函數,調用方式為:cout.precision(5); 用于指定浮點數的有效位數(非定點方式)。系統默認是非定點方式。
(2) setprecision:流操縱算子,調用方式為:cout << setprecision(5); 用于指定浮點數的有效位數(非定點方式)和指定浮點數的小數后的有效位數(非定點方式)。定點方式:小數點必須出現在個位數后面。
(3) 注意:
- 當位數超過精度時會四舍五入。
- setprecision方式會持續有效,直到設置新的精確度。
- setprecision操縱算子也需要添加頭文件iomanip。
- 在非定點方式下,setprecision可能會使用科學計數法來表示。
(4) setiosflags(ios::fixed):以小數點位置固定的方式來輸出(可以簡單用cout << fixed;)。另外,cout << scientific表示采用科學計數法。
(5) resetiosflags(ios::fixed):取消以小數點位置固定的方式來輸出。
(6) 代碼示例:
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <iomanip> using namespace std;int main() {float f = 1234567.89;int n = 123456;//默認是非定點方式cout << "*****非定點******" << endl;cout << setprecision(6);//設置浮點數有效位數為6cout << f << endl;//由于非定點方式且規定只能有6位,因此用科學計數法顯示cout << n << endl;//浮點數的操縱算子不影響整數//修改為定點方式cout << "*****定點********" << endl;cout << setiosflags(ios::fixed);cout << f << endl;//小數點后有6位,不夠就補0//修改為非定點方式cout << "*****非定點******" << endl;cout << resetiosflags(ios::fixed);cout << f << endl;//由于非定點方式且規定只能有6位,因此用科學計數法顯示return 0; }
3. 域寬的流操縱算子
(1) setw:流操縱算子,用于設置域寬。調用方式:cout << setw(5)或cin >>?setw(5)。
(2) width:成員函數,用于設置域寬。調用方式:cout.width(5)或cin.width(5)。
(3) 注意:域寬的流操縱算子是一次性的,每次輸入輸出前都需要指定寬度。
(4) 代碼示例:
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <iomanip> using namespace std;int main() {int m = 4;char string[10];cin >> setw(5);//設置輸入寬度while (cin >> string) {cout << setw(m++);//設置輸出寬度cout << string << endl;cin >> setw(5);}return 0; }
(5) 結果解釋:
- 第一行是我們輸入的數據1234567890.
- 第二行輸出1234。首先,設置輸入寬度為5(實際上只接收4個字符,最后自動加'\0'),那么string里就是1234‘\0’。其次,設置輸出寬度為4(設置完后m自增為5),那么輸出4個字符即1234.
- 第三行輸出" 5678"。首先,設置輸入寬度為5(實際上只接收4個字符,最后自動加'\0'),那么string里就是5678‘\0’。其次,設置輸出寬度為5(設置完后m自增為6),那么輸出5個字符即空格+5678.
- 第四行輸出"? ? 90"。首先,設置輸入寬度為5(實際上只接收4個字符,最后自動加'\0'),那么string里就是90‘\0’。其次,設置輸出寬度為6(設置完后m自增為7),那么輸出6個字符即4個空格+90.
4. 其他的流操縱算子
(1) cout << showpos; 非負數顯示正號。
(2) cout << noshowpos; 非負數不顯示正號。
(3) cout << setfill(*); 寬度不足用*填補。
(4) cout << right; 右對齊,寬度不足則左邊填充。
(5) cout << left; 左對齊,寬度不足則右邊填充。
(6) cout << internal; 在負號和數字之間填充。
(7) 綜合案例:
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <iomanip> using namespace std;int main() {int i = 141;double x = 1234567.89, y = 12.34567;//1) 8d 141 215cout << "1) " << hex << i << " " << dec << i << " " << oct << i << endl;//2) 1.2346e+006 12.346cout << "2) " << setprecision(5) << x << " " << y << endl;//3) 1234567.89000 12.34567cout << "3) " << fixed << setprecision(5) << x << " " << y << endl;//4) 1.23457e+006 1.23457e+001cout << "4) " << scientific << setprecision(5) << x << " " << y << endl;//5) ***+12.10000cout << "5) " << showpos << right << fixed << setprecision(5) << setfill('*') << setw(12) << 12.1 << endl;//6) 12.10000****cout << "6) " << noshowpos << left << fixed << setprecision(5) << setfill('*') << setw(12) << 12.1 << endl;//7) ****12.10000cout << "7) " << noshowpos << right << fixed << setprecision(5) << setfill('*') << setw(12) << 12.1 << endl;//8) -***12.10000cout << "8) " << showpos << right << fixed << setprecision(5) << internal << setfill('*') << setw(12) << -12.1 << endl;//9) 12.10000cout << "9) " << noshowpos << fixed << setprecision(5) << 12.1 << endl;return 0; }
5. 用戶自定義流操縱算子
(1) 格式:
ostream& 函數名(ostream& cout) {//執行的操作return cout; }
(2) 代碼示例:定義tab流操縱算子。
#define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std;ostream& tab(ostream& output) {return output << '\t'; }int main() {cout << "a" << tab << "b" << endl;return 0; }
(3) 底層解釋:由于iostream里對<<進行了重載(使用成員函數方式),即ostream& operator << (ostream& (*p) (ostream&)); 其中ostream& (*p) (ostream&)是函數指針,能夠根據函數名找到對應的函數并執行函數體,同時內部還返回了*this就是對象本身。因此,在上述示例中,tab就是一個函數名,會執行tab的函數體。
三、文件讀寫
1. 文本文件的讀寫
(1) 創建讀文件對象:ifstream srcFile("in.txt", ios::in);
(2) 創建寫文件對象:ofstream destFile("out.txt", ios::out);
(3) 從文件中讀取字符:srcFile >> x;
(4) 將字符寫入文件:destFile << x;
(5) 注意:
- 寫文件對象中ios::out選項:刪除原有內容,寫入新內容。
- 寫文件對象中ios::app選項:在原內容后面追加新內容。
- 讀寫文件對象中ios::binary選項:以二進制方式寫入/讀取。
- ifstream和ofstream換成fstream也行。
(6) 代碼示例:將in.txt中的內容1 234 9 45 6 879排序,并存到out.txt中。
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <fstream> #include <vector> #include <algorithm> using namespace std;int main() {//1.打開文件in.txtifstream srcFile("./in.txt", ios::in);if (!srcFile) {cout << "srcFile文件打開失敗!" << endl;return -1;}//2.讀取文本字符并加入vector中int readInt;vector<int> v;while (srcFile >> readInt) {v.push_back(readInt);}//3.對vector中元素排序sort(v.begin(), v.end());//4.將排序結果寫入out.txtofstream outFile("./out.txt", ios::out);if (!outFile) {cout << "outFile文件打開失敗!" << endl;return -1;}for (int i = 0; i < v.size(); i++) {outFile << v[i] << " ";}//5.關閉文件srcFile.close();outFile.close();return 0; }
? ? ? ? ?
2. 二進制文件的讀寫
(1) 創建讀寫對象:方式與文本文件相同,但是選項要或(|)上ios::binary選項!
(2) 讀文件:使用ifstream和fstream中的成員函數read函數。
- 函數原型:istream& read(char* s, long n);
- 功能:將文件讀指針指向的地方的n個字節內容,讀取到內存地址s,然后讀指針向后移動n字節。
(3) 寫文件:使用ofstream和fstream中的成員函數write函數。
- 函數原型:istream& write(const char* s, long n);
- 功能:將內存地址s處的n個字節內容,寫入到寫指針指向的位置,然后寫指針向后移動n字節。
(4) 代碼示例:將整數120寫入二進制文件,再從該二進制文件中讀取整數。
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <fstream> using namespace std;int main() {//寫入ret于二進制文件out.dat中int ret = 120;ofstream outFile("./out.dat", ios::out | ios::binary);outFile.write((const char*)(&ret), sizeof(int));outFile.close();//從out.dat中讀取一個整數int readInt;ifstream inFile("./out.dat", ios::in | ios::binary);inFile.read((char*)(&readInt), sizeof(int));inFile.close();//顯示讀取的整數cout << readInt << endl;return 0; }
3. 文件讀寫指針
(1) 介紹:
- 對于輸入文件,有一個讀指針。
- 對于輸出文件,有一個寫指針。
- 對于輸入輸出文件,有一個讀寫指針。
- 讀/寫指針標識文件操作的當前位置。
(2) 讀指針相關操作:
- tellg():獲取讀指針的位置。調用方式:"輸出對象.tellg()"。
- seekg(int i):移動讀指針至第i個字節處。調用方式:"輸出對象.seekg(i)"。
- seekg(int i, ios::beg):移動至距文件開始的第i個位置。
- seekg(int i, ios::cur):移動至當前位置后的第i位置。
- seekg(int i, ios::end):移動至距文件末尾的第i個位置。(常用于統計文本的字符數)
(3) 寫指針相關操作:
- tellp():獲取寫指針的位置。調用方式:"輸出對象.tellp()"。
- seekp(int i):移動寫指針至第i個字節處。調用方式:"輸出對象.seekp(i)"。
- seekp(int i, ios::beg):移動至距文件開始的第i個位置。
- seekp(int i, ios::cur):移動至當前位置后的第i位置。
- seekp(int i, ios::end):移動至距文件末尾的第i個位置。
(4) 代碼示例:輸出A~Z于test.txt中,并且每兩個字符間空兩格。
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <fstream> using namespace std;int main() {ofstream outFile("./test.txt", ios::out);/* 輸出A~Z于test.txt中,并且每兩個字符間空兩格*/for (char i = 'A'; i <= 'Z'; i++) {//獲取寫文件指針位置int location = outFile.tellp();//寫入字符outFile << i;//文件指針會自動+1,再使用seekp跳到后兩個位置outFile.seekp(2, ios::cur);//打印測試信息cout << location << endl;}//關閉文件outFile.close();return 0; }
4. 文本文件和二進制文件區別
(1) 不同操作系統下換行符號區別:
- Linux下的換行:'\n'(ASCII:0x0a)
- Windows下的換行:'\r\n'(ASCII:0x0d0a)
- MacOS下的換行:'\r'(ASCII:0x0d)
- 由于ASCII碼不同,Linux和MacOS的文本文件在Windows中的記事本打開時不換行。
(2)?文本文件和二進制文件區別:
- Linux下打開文件,用不用ios::binary沒區別。
- Windows下打開文件,如果不用ios::binary,則會造成①讀取文件時,所有的'\r\n'都會被當作'\n'處理,因此會少讀了一個字符'\r'。②寫入文件時,寫入單獨的'\n'時,系統會自動加'\r',因此多寫了一個字符'\r'。
- 一般來說,使用二進制文件更加節省空間。例如,保存123456,若保存于文本文件則需要6個字節,而保存于二進制文件用一個int的字節就行了。