C++文件IO流及stringstream流讀寫文件和字符串操作詳解
一、引入
int main() { string str; while (cin >> str) { cout << str << endl; } return 0; }
我們在OJ的時候經(jīng)常會用到while(cin >> str),這里的流提取實際上是個阻塞操作,只要緩沖區(qū)還有數(shù)據(jù)就繼續(xù)讀,默認(rèn)以空格或者換行結(jié)束,有空格說明是把兩段字符串尾插到str。
那么它是怎么結(jié)束呢?
答案是輸入[Ctrl]-c
或者[Ctrl]-z + 換行
。
[Ctrl]-c
是發(fā)送信號結(jié)束進程。
[Ctrl]-z + 換行
是通過返回值條件判斷結(jié)束while循環(huán),具體看下面講解。
二、自定義類型隱式類型轉(zhuǎn)換
cin >> str
的返回值是一個istream類
實際上返回的就是cin對象。而c++98支持了隱式類型轉(zhuǎn)換,把istream轉(zhuǎn)換為bool,所以能夠條件判斷。
具體是怎么轉(zhuǎn)換的呢?
看下面這個例子:
class A { public: A(int a) : _a(a) {} private: int _a; }; int main() { // 內(nèi)置類型轉(zhuǎn)換成自定義類型 A a = 1; return 0; }
這里按道理來說是構(gòu)造一個臨時對象再拷貝構(gòu)造,而編譯器優(yōu)化成了直接構(gòu)造。如果沒有單參數(shù)的構(gòu)造函數(shù)就無法轉(zhuǎn)換。
那如果我們想要讓自定義類型轉(zhuǎn)換成內(nèi)置類型呢?
直接int aa = a;
肯定會報錯。
但是我們可以加一個特殊的重載函數(shù)。
class A { public: A(int a) : _a(a) {} operator int() { return _a; } private: int _a; }; int main() { // 內(nèi)置類型轉(zhuǎn)換成自定義類型 A a = 1; // 自定義類型轉(zhuǎn)化成內(nèi)置類型 int aa = a; cout << aa << endl; return 0; }
而我們上面說的把istream轉(zhuǎn)化成bool類型就是類似這樣實現(xiàn)的。
operator bool()
里面會檢查是特殊字符([Ctrl]-z
)就會返回false。
三、sync_with_stdio同步
我們知道cin和scanf都有自己的緩沖區(qū),而如果我們用scanf寫入再用cout輸出,就會導(dǎo)致速度變慢很多(緩沖區(qū)拷貝)。
而sync_with_stdio函數(shù)是一個“是否兼容stdio”的開關(guān),C++為了兼容C,保證程序在使用了std::printf和std::cout的時候不發(fā)生混亂,將輸出流綁到了一起。
決定C++標(biāo)準(zhǔn)streams(cin,cout,cerr…)是否與相應(yīng)的C標(biāo)準(zhǔn)程序庫文件(stdin,stdout,stderr)同步,也就是是否使用相同的stream緩沖區(qū),缺省情況是同步的,但由于同步會帶來某些不必要的負(fù)擔(dān),因此該函數(shù)作用就是我們自己可以取消同步 。
#include <iostream> int main() { std::ios::sync_with_stdio(false); std::cin.tie(0); // IO }
四、文件IO流
文件的讀寫有兩種:
1?? 二進制讀寫
2?? 文本讀寫
ofstream是寫入文件,而ifstream是從文件中讀取。
4.1 open和close文件
這里的參數(shù)表示我們想以什么樣的方式打開文件。
比方說當(dāng)我們想用二進制的方式打開文件:
ofs.open ("test.txt", std::ofstream::out | std::ofstream::binary)
而我們也可以在構(gòu)造的時候直接傳進參數(shù)。
ofstream ofs("test.txt", std::ios_base::out | std::ios_base::binary)
4.2 寫入文件與讀出文件
struct ServerInfo { char _address[32]; int _port; }; struct Config { public: Config(const char* filename) : _filename(filename) {} void Write(ServerInfo info) { ofstream ofs("test.txt", std::ios_base::out | std::ios_base::binary); ofs.write((char*)&info, sizeof info); } void Read(ServerInfo& info) { ifstream ifs("test.txt", std::ios_base::in | std::ios_base::binary); ifs.read((char*)&info, sizeof info); } private: string _filename; }; int main() { Config con("text.txt"); ServerInfo si = { "aaaaaa", 910 }; con.Write(si); return 0; }
而我們也可以把數(shù)據(jù)讀回來。
int main() { Config con("text.txt"); //ServerInfo si = { "aaaaaa", 910 }; //con.Write(si); ServerInfo si; con.Read(si); cout << si._address << " " << si._port << endl; return 0; }
可以看到內(nèi)存中和寫出去顯示出來的不一樣。
當(dāng)然我們可以用文本讀寫的方式。
struct ServerInfo { char _address[32]; int _port; }; struct Config { public: Config(const char* filename) : _filename(filename) {} void Write(ServerInfo info) { ofstream ofs(_filename); // 重載 ofs << info._address << endl; ofs << info._port << endl; } void Read(ServerInfo& info) { ifstream ifs(_filename); // 重載 ifs >> info._address; ifs >> info._port; } private: string _filename; }; int main() { Config con("text.txt"); ServerInfo si = { "aaaaaa", 910 }; con.Write(si); /*ServerInfo si; con.Read(si); cout << si._address << " " << si._port << endl;*/ return 0; }
五、stringstream流的使用
在程序中如果想要使用stringstream,必須要包含頭文件。在該頭文件下,標(biāo)準(zhǔn)庫三個類:
istringstream、ostringstream 和 stringstream,分別用來進行流的輸入、輸出和輸入輸出操作。
5.1 將數(shù)值類型數(shù)據(jù)格式化為字符串
int main() { int a = 123; const char* b = "456"; double c = 78.9; ostringstream os; os << a; os << b; os << c; cout << os.str() << endl; return 0; }
當(dāng)然我們也可以把每個數(shù)據(jù)都提取出來。但此時輸入的時候就要空格或者換行隔開。
int main() { int a = 123; const char* b = "456"; double c = 78.9; ostringstream os; os << a << " "; os << b << " "; os << c << " "; string ret = os.str(); cout << ret << endl; int d; char e[20]; double f; istringstream is(ret); is >> d >> e >> f; cout << d << " "; cout << e << " "; cout << e << " "; return 0; }
5.2 序列化和反序列化
序列化指的是將一個內(nèi)存對象轉(zhuǎn)化成一串字節(jié)數(shù)據(jù)(存儲在一個字節(jié)數(shù)組中),可用于保存到本地文件或網(wǎng)絡(luò)傳輸。反序列化就是將字節(jié)數(shù)據(jù)還原成內(nèi)存對象。
總結(jié)
序列化:將對象變成字節(jié)流的形式傳出去。
反序列化:從字節(jié)流恢復(fù)成原來的對象。
簡單來說,對象序列化通經(jīng)常使用于兩個目的:
1?? 將對象存儲于硬盤上,便于以后反序列化使用;
2?? 在網(wǎng)絡(luò)上傳送對象的字節(jié)序列
我們現(xiàn)在模擬一個聊天的發(fā)送窗口。
class Date { friend ostream& operator << (ostream& out, const Date& d); friend istream& operator >> (istream& in, Date& d); public: Date(int year = 1, int month = 1, int day = 1) :_year(year) , _month(month) , _day(day) {} private: int _year; int _month; int _day; }; istream& operator >> (istream& in, Date& d) { in >> d._year >> d._month >> d._day; return in; } ostream& operator << (ostream& out, const Date& d) { out << d._year << " " << d._month << " " << d._day; return out; } struct ServerInfo { friend istream& operator >> (istream& in, ServerInfo& si); friend ostream& operator << (ostream& out, ServerInfo& si); string _name;// 昵稱 Date _d;// 時間 string _msg;// 信息 }; istream& operator >> (istream& in, ServerInfo& si) { in >> si._name >> si._d >> si._msg; return in; } ostream& operator << (ostream& out, ServerInfo& si) { out << si._name << " "; out << si._d << " "; out << si._msg << " "; return out; } int main() { ServerInfo p{ "海闊天空", {2023, 4, 19}, "hello" }; stringstream os; os << p; string ret = os.str(); ServerInfo is; stringstream oss(ret); oss >> is; cout << "-------------------------------------------------------" << endl; cout << "昵稱:" << is._name << " "; cout << is._d << endl; cout << is._name << ": " << is._msg << endl; cout << "-------------------------------------------------------" << endl; return 0; }
到此這篇關(guān)于C++文件IO流及stringstream流讀寫文件和字符串操作詳解的文章就介紹到這了,更多相關(guān)C++文件IO流內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用VS2022開發(fā)在線遠程編譯部署的C++程序(圖文詳解)
這篇文章主要介紹了使用VS2022開發(fā)可以在線遠程編譯部署的C++程序,本文分步驟通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-12-12C++?OpenGL實現(xiàn)旋轉(zhuǎn)立方體的繪制
這篇文章主要主要為大家詳細介紹了如何利用C++和OpenGL實現(xiàn)旋轉(zhuǎn)立方體的繪制,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起動手嘗試一下2022-07-07Qt利用QSortFilterProxyModel代理實現(xiàn)自定義排序與聯(lián)合過濾
QsortFilterProxyModel類用來為model和view之間提供強大的排序和過濾支持。這篇文章將利用QSortFilterProxyModel代理實現(xiàn)自定義排序與聯(lián)合過濾,需要的可以參考一下2022-11-11《C++ Primer》隱式類類型轉(zhuǎn)換學(xué)習(xí)整理
在本篇文章里小編給大家整理的是關(guān)于《C++ Primer》隱式類類型轉(zhuǎn)換學(xué)習(xí)筆記內(nèi)容,需要的朋友們參考下。2020-02-02