摘要:在使用時候必須要包含頭文件并引入標準命名空間。在該頭文件下,標準庫三個類進行流的輸入進行流的輸出進行流的輸入輸出將結構體的內容轉換成字符串字符串的內容輸出到結構體當中注意實際是在其底層維護了一個類型的對象用來保存結果。
C語言中我們用到的最頻繁的輸入輸出方式就是scanf ()與printf()。
scanf(): 從標準輸入設備(鍵盤)讀取數據,并將值存放在變量中。
printf(): 將指定的文字/字符串輸出到標準輸出設備(屏幕,網卡,顯示器等)。注意寬度輸出和精度輸出控制。
C語言借助了相應的緩沖區來進行輸入與輸出。如下圖所示
對輸入輸出緩沖區的理解:
(1).可以屏蔽掉低級I/O的實現,低級I/O的實現依賴操作系統本身內核的實現,所以如果能夠屏蔽這部分的差異,可以很容易寫出可移植的程序。
(2).可以使用這部分的內容實現“行”讀取的行為,對于計算機而言是沒有“行”這個概念,有了這部分,就可以定義“行”的概念,然后解析緩沖區的內容,返回一個“行”。
C++標準庫提供了一組豐富的輸入/輸出功能,本文重點講解C++編程中最常見的 I/O 操作
C++的 I/O 發生在流中,流是字節序列,如果字節流是從設備(如鍵盤,磁盤驅動器,網絡連接等)流向內存,這叫做輸入操作,如果字節流是從內存流向設備,這叫做輸出操作。
標準輸出流 :
預定義的對象 cout 是 ostream 類的一個實例,cout 對象"連接"到標準輸出設備,通常是顯示屏。
標準輸入流 :
預定義的對象 cin 是 istream 類的一個實例,cin 對象附屬到標準輸入設備,通常是鍵盤。
我們來研究下面這一段代碼
#include #include using namespace std;struct Student{ string _name; int _age;};int main(){ Student s; cin >> s._name >> s._age; cout << s._name << " " << s._age << endl; scanf("%s%d", s._name.c_str(), &s._age); printf("%s %d", s._name.c_str(), s._age);}
這段代碼看上去沒有什么問題,但如果我們第二次輸入的字符串過長,會導致程序崩潰,原因如下 :
string內部會有一個_Buf數組,當存儲的字符串大小小于15字節時,不會去堆上開辟空間存儲字符串,會將字符串存儲在_Buf數組中,但無論第一次輸入的字符串大小是大于15字節還是小于15字節,第二次如果輸入過長,都會導致程序崩潰,原因在于第二次是用scanf進行輸入,使用scanf輸入,不會影響string的size和capacity,所以輸入過長就會越界寫入
#include #include using namespace std;struct Student{ string _name; int _age;};int main(){ Student s; cin >> s._name >> s._age; cout << s._name << " " << s._age << endl; scanf("%s%d", s._name.c_str(), &s._age); cout << s._name << " " << s._age << endl;}
這段代碼和上一段代碼相比只是最后的輸出使用了cout,跟上面一樣,如果輸入過長也會導致越界寫入,除此之外,就算輸入的長度在合法的范圍內,打印出來的結果也不是我們想要的,原因是cout在輸出時是根據string的size來輸出的,而scanf輸入時并沒有改變string的size,所以打印結果不是我們想要的,上面的printf如果輸入的長度在合法的范圍內,打印結果就是我們想要的,原因是printf打印字符串時是根據’/0’的位置來判斷的.
想要解決上面的兩個問題,我們提前把空間開好即可
#include #include using namespace std;struct Student{ string _name; int _age;};int main(){ Student s; cin >> s._name >> s._age; cout << s._name << " " << s._age << endl; s._name.resize(100); // 提前開好空間 scanf("%s%d", s._name.c_str(), &s._age); printf("%s %d/n", s._name.c_str(), s._age); cout << s._name << " " << s._age << endl;}
因此,建議大家在C++中盡量去用cin和cout,用cout和cin不方便的地方,再去用scanf和printf(格式控制輸出時)
C++系統實現了一個龐大的類庫,其中ios為基類,其他類都是直接或間接派生自ios類
C++標準庫提供了4個全局流對象cin、cout、cerr、clog,使用cout進行標準輸出,即數據從內存流向控制臺(顯示器)。使用cin進行標準輸入即數據通過鍵盤輸入到程序中,同時C++標準庫還提供了cerr用來進行標準錯誤的輸出,以及clog進行日志的輸出,從上圖可以看出,cout、cerr、clog是ostream類的三個不同的對象,因此這三個對象現在基本沒有區別,只是應用場景不同。
在使用時候必須要包含頭文件并引入std標準命名空間。
注意:
(1). cin為緩沖流。鍵盤輸入的數據保存在緩沖區中,當要提取時,是從緩沖區中拿。如果一次輸入過多,會留在那兒慢慢用,如果輸入錯了,必須在回車之前修改,如果回車鍵按下就無法挽回了。只有把輸入緩沖區中的數據取完后,才要求輸入新的數據。
(2). 輸入的數據類型必須與要提取的數據類型一致,否則出錯。出錯只是在流的狀態字state中對應位置,程序繼續。
(3). 空格和回車都可以作為數據之間的分格符,所以多個數據可以在一行輸入,也可以分行輸入。但如果是字符型和字符串,則空格(ASCII碼為32)無法用cin輸入,字符串中也不能有空格。回車符也無法讀入。
#include using namespace std;int main(){ // 輸入 hello world string a; cin >> a; cout << a << endl; // hello cin >> a; cout << a << endl; // world getline(cin,a); cout << a << endl;}
(4). cin和cout可以直接輸入和輸出內置類型數據,原因:標準庫已經將所有內置類型的輸入和輸出全部重載了
(5). 對于自定義類型,如果要支持cin和cout的標準輸入輸出,需要對<<和>>進行重載
(6). 循環輸入結構
string str;while(cin>>str){ cout<<str<<endl;}char buff[100];while(scanf("%s",buff) != EOF){ printf("%s/n",buff);}
兩種方式都能達到循環輸入的目的,使用ctrl + c終止輸入
(1). cin>>str 等同于 istream& operator>>(cin,str),返回值為cin對象,通過operator bool()來判斷是否有讀取錯誤
(2). scanf函數當讀取發生錯誤或讀到文件末尾,會返回EOF
ofstream
輸出文件流,用于創建文件并向文件寫入信息
ifstream
輸入文件流,用于從文件讀取信息
fstream
文件流,且同時具有 ofstream 和 ifstream 兩種功能,這意味著它可以創建文件,向文件寫入信息,從文件讀取信息
文件常見的打開方式 :
(1). in 以讀的方式打開文件
(2). out 以寫的方式打開文件
(3). binary 以二進制方式對文件進行操作
(4). ate 輸出位置從文件的末尾開始
(5). app 以追加的方式對文件進行寫入
(6). trunc 先將文件內容清空再打開文件
常用成員函數
(1). put 插入一個字符到文件
(2). write 插入一段字符到文件
(3). get 從文件提取字符
(4). read 從文件提取多個字符
(5). tellg 獲取當前字符在文件當中的位置
(6). seekg 設置對文件進行操作的位置
(7). >>運算符重載 將數據形象地以“流”的形式進行輸入(用于文本文件)
(8). <<運算符重載 將數據形象地以“流”的形式進行輸出(用于文本文件)
以文本的形式操作文件
對文本文件進行寫入操作
//以文本的形式對文件進行寫入void Write(){ ofstream outfile("test.txt"); // 以寫的方式打開文件 outfile.put("c"); // 向文件寫入一個字符"c" outfile.write("hello world",5); // 向文件寫入長度為n的字符串 outfile << "hehe"; // 向文件寫入字符串 outfile.close(); // 關閉文件}
對文件文件進行讀取操作
//以文本的形式對文件進行讀取void ReadTxt(){ ifstream infile("test.txt"); // seekg(),tellg() char c, c1, c2; infile.seekg(2); infile >> c; infile.seekg(3, ios::beg); infile >> c1; infile.seekg(-1,ios::end); infile >> c2; cout << c << endl; cout << c1 << endl; cout << c2 << endl; // get char c; while (infile.get(c)) { cout << c; } cout << endl; // read infile.seekg(0, ios::end); int length = infile.tellg(); infile.seekg(0, ios::beg); char* buffer = new char[length]; infile.read(buffer, length); if (infile) { cout << buffer << endl; } delete[]buffer; // >> infile.seekg(0, ios::end); int length = infile.tellg(); infile.seekg(0, ios::beg); char* buffer = new char[length]; infile >> buffer; cout << buffer << endl;}
對二進制文件進行寫入操作
void write(){ ofstream outfile("test.bin",ios::out | ios::binary); outfile.put("l"); outfile.write("lyp hello linux",10); }
對二進制文件進行讀取操作
void read(){ ifstream infile("test.bin", ios::in | ios::binary); // get char c; while (infile.get(c)) { cout << c; } cout << endl; // read infile.seekg(0, ios::end); int length = infile.tellg(); infile.seekg(0, ios::beg); char* buffer = new char[length]; infile.read(buffer, length); if (infile) { cout << buffer << endl; } delete[]buffer;}
在C語言中,如果想要將一個整形變量的數據轉化為字符串格式,我們一般有以下兩種方式
(1). itoa
int a = 20;char buffer[10];itoa(a,buffer,10); // 將數字轉換成10進制字符
(2). sprintf
struct ServerInfo{ char _ip[20]; int _port;};int main(){ ServerInfo info = {"2020.110.400.83",250}; char buffer[128]; // 序列化,將結構體中的內容轉換成字符串 sprintf(buffer, "%s %d", info._ip, info._port); // 加空格,在buffer數組里就有空格 // 反序列化,將數組的內容讀到結構體中 ServerInfo rinfo; sscanf(buffer, "%s %d", rinfo._ip, &rinfo._port);}
但是兩個函數在轉化時,都得需要先給出保存結果的空間,那空間要給多大呢,就不太好界定,而且轉化格式不匹配時,可能還會得到錯誤的結果甚至程序崩潰。
在C++中,可以使用stringstream類對象來避開此問題。
在程序中如果想要使用stringstream類,必須要包含頭文件。在該頭文件下,標準庫三個類:
(1). istringstream 進行流的輸入
(2). ostringstream 進行流的輸出
(3). stringstream 進行流的輸入輸出
#include #include using namespace std;struct ServerInfo{ char _ip[20]; int _port;};int main(){ ServerInfo info = {"2020.110.400.83",250}; // 將結構體的內容轉換成字符串 stringstream sm; sm << info._ip << " " << info._port; string buffer = sm.str(); cout << buffer << endl; // 字符串的內容輸出到結構體當中 stringstream sm; sm.str("2020.110.400.83 250"); ServerInfo rinfo; sm >> rinfo._ip >> rinfo._port; stringstream sm("2020.110.400.83 250"); ServerInfo rinfo; sm >> rinfo._ip >> rinfo._port; }
注意:
(1). stringstream實際是在其底層維護了一個string類型的對象用來保存結果。
(2). 多次數據類型轉化時,一定要用clear()來清空,才能正確轉化,但clear()不會將stringstream底層的string對象清空。
(3). 可以使用s. str("")方法將底層string對象設置為""空字符串。
(4). 可以使用s.str()將讓stringstream返回其底層的string對象。
(5). stringstream使用string類對象代替字符數組,可以避免緩沖區溢出的危險,而且其會對參數類型進行推演,不需要格式化控制,也不會出現格式化失敗的風險,因此使用更方便,更安全。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/121139.html
摘要:的選擇器允許單個線程監視多個輸入通道。一旦執行的線程已經超過讀取代碼中的某個數據片段,該線程就不會在數據中向后移動通常不會。 1、引言 很多初涉網絡編程的程序員,在研究Java NIO(即異步IO)和經典IO(也就是常說的阻塞式IO)的API時,很快就會發現一個問題:我什么時候應該使用經典IO,什么時候應該使用NIO? 在本文中,將嘗試用簡明扼要的文字,闡明Java NIO和經典IO之...
摘要:我的是忙碌的一年,從年初備戰實習春招,年三十都在死磕源碼,三月份經歷了阿里五次面試,四月順利收到實習。因為我心理很清楚,我的目標是阿里。所以在收到阿里之后的那晚,我重新規劃了接下來的學習計劃,將我的短期目標更新成拿下阿里轉正。 我的2017是忙碌的一年,從年初備戰實習春招,年三十都在死磕JDK源碼,三月份經歷了阿里五次面試,四月順利收到實習offer。然后五月懷著忐忑的心情開始了螞蟻金...
摘要:基礎的端到端的基準測試顯示大約比快八倍。所謂單線程,就是指一次只能完成一件任務。在服務器端,異步模式甚至是唯一的模式,因為執行環境是單線程的,如果允許同步執行所有請求,服務器性能會急劇下降,很快就會失去響應。 模塊 Node.js 提供了exports 和 require 兩個對象,其中 exports 是模塊公開的接口,require 用于從外部獲取一個模塊的接口,即所獲取模塊的 e...
摘要:前言本篇主要講解中的機制和網絡通訊中處理高并發的分為兩塊第一塊講解多線程下的機制第二塊講解如何在機制下優化資源的浪費服務器單線程下的機制就不用我介紹了,不懂得可以去查閱下資料那么多線程下,如果進行套接字的使用呢我們使用最簡單的服務器來幫助大 前言 本篇主要講解Java中的IO機制和網絡通訊中處理高并發的NIO 分為兩塊:第一塊講解多線程下的IO機制第二塊講解如何在IO機制下優化CPU資...
閱讀 952·2021-11-24 09:39
閱讀 2689·2021-09-26 09:55
閱讀 14154·2021-08-23 09:47
閱讀 3577·2019-08-30 15:52
閱讀 848·2019-08-29 13:49
閱讀 997·2019-08-23 18:00
閱讀 843·2019-08-23 16:42
閱讀 1634·2019-08-23 14:28