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