C++文件IO流及stringstream流讀寫文件和字符串操作詳解
一、引入
int main()
{
string str;
while (cin >> str)
{
cout << str << endl;
}
return 0;
}

我們在OJ的時候經常會用到while(cin >> str),這里的流提取實際上是個阻塞操作,只要緩沖區(qū)還有數(shù)據(jù)就繼續(xù)讀,默認以空格或者換行結束,有空格說明是把兩段字符串尾插到str。
那么它是怎么結束呢?
答案是輸入[Ctrl]-c或者[Ctrl]-z + 換行。
[Ctrl]-c是發(fā)送信號結束進程。
[Ctrl]-z + 換行是通過返回值條件判斷結束while循環(huán),具體看下面講解。
二、自定義類型隱式類型轉換
cin >> str的返回值是一個istream類

實際上返回的就是cin對象。而c++98支持了隱式類型轉換,把istream轉換為bool,所以能夠條件判斷。
具體是怎么轉換的呢?
看下面這個例子:
class A
{
public:
A(int a)
: _a(a)
{}
private:
int _a;
};
int main()
{
// 內置類型轉換成自定義類型
A a = 1;
return 0;
}
這里按道理來說是構造一個臨時對象再拷貝構造,而編譯器優(yōu)化成了直接構造。如果沒有單參數(shù)的構造函數(shù)就無法轉換。
那如果我們想要讓自定義類型轉換成內置類型呢?
直接int aa = a;肯定會報錯。
但是我們可以加一個特殊的重載函數(shù)。
class A
{
public:
A(int a)
: _a(a)
{}
operator int()
{
return _a;
}
private:
int _a;
};
int main()
{
// 內置類型轉換成自定義類型
A a = 1;
// 自定義類型轉化成內置類型
int aa = a;
cout << aa << endl;
return 0;
}
而我們上面說的把istream轉化成bool類型就是類似這樣實現(xiàn)的。
operator bool() 里面會檢查是特殊字符([Ctrl]-z )就會返回false。
三、sync_with_stdio同步
我們知道cin和scanf都有自己的緩沖區(qū),而如果我們用scanf寫入再用cout輸出,就會導致速度變慢很多(緩沖區(qū)拷貝)。
而sync_with_stdio函數(shù)是一個“是否兼容stdio”的開關,C++為了兼容C,保證程序在使用了std::printf和std::cout的時候不發(fā)生混亂,將輸出流綁到了一起。
決定C++標準streams(cin,cout,cerr…)是否與相應的C標準程序庫文件(stdin,stdout,stderr)同步,也就是是否使用相同的stream緩沖區(qū),缺省情況是同步的,但由于同步會帶來某些不必要的負擔,因此該函數(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ù)表示我們想以什么樣的方式打開文件。
比方說當我們想用二進制的方式打開文件:
ofs.open ("test.txt", std::ofstream::out | std::ofstream::binary)
而我們也可以在構造的時候直接傳進參數(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;
}

可以看到內存中和寫出去顯示出來的不一樣。
當然我們可以用文本讀寫的方式。
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,必須要包含頭文件。在該頭文件下,標準庫三個類:
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;
}

當然我們也可以把每個數(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 序列化和反序列化
序列化指的是將一個內存對象轉化成一串字節(jié)數(shù)據(jù)(存儲在一個字節(jié)數(shù)組中),可用于保存到本地文件或網(wǎng)絡傳輸。反序列化就是將字節(jié)數(shù)據(jù)還原成內存對象。
總結
序列化:將對象變成字節(jié)流的形式傳出去。
反序列化:從字節(jié)流恢復成原來的對象。
簡單來說,對象序列化通經常使用于兩個目的:
1?? 將對象存儲于硬盤上,便于以后反序列化使用;
2?? 在網(wǎng)絡上傳送對象的字節(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;
}

到此這篇關于C++文件IO流及stringstream流讀寫文件和字符串操作詳解的文章就介紹到這了,更多相關C++文件IO流內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C++利用函數(shù)動態(tài)創(chuàng)建二維數(shù)組
這篇文章主要為大家詳細介紹了C++利用函數(shù)動態(tài)創(chuàng)建二維數(shù)組,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-09-09
OpenCV使用稀疏光流實現(xiàn)視頻對象跟蹤的方法詳解
這篇文章主要為大家詳細介紹了OpenCV如何使用稀疏光流實現(xiàn)視頻對象跟蹤功能,文中的示例代碼講解詳細,具有一定的借鑒價值,需要的可以參考一下2023-02-02
C++實現(xiàn)LeetCode(6.字型轉換字符串)
這篇文章主要介紹了C++實現(xiàn)LeetCode(6.字型轉換字符串),本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下2021-07-07
Visual Studio 如何創(chuàng)建C/C++項目問題
這篇文章主要介紹了Visual Studio 如何創(chuàng)建C/C++項目問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-02-02

