C++IO体系
ostream/istream 更好的支持自定义类型对象的流插入和流提取,自定义类型,可以自己重载,控制流提取和流插入的方式
![](https://cdn.jsdelivr.net/gh/atongrun/ImageHost@main/202301151704396.png)
输入输出
c输入
![](https://cdn.jsdelivr.net/gh/atongrun/ImageHost@main/202301151712088.png)
c++输入
1 2 3 4 5
| cin >> str;
year = stoi(str.substr(0, 4)); mon = stoi(str.substr(4, 2)); day = stoi(str.substr(6, 2));
|
![](https://cdn.jsdelivr.net/gh/atongrun/ImageHost@main/202301151724063.png)
ctrl+z+换行结束输入
为什么可以用上边循环的写法呢?是因为cin的对象可以隐式类型转换成bool(调用operator bool),在流里面读到错误或者结束标志的时候,会返回false
![](https://cdn.jsdelivr.net/gh/atongrun/ImageHost@main/202301151732425.png)
举例详解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| class A { public: A(int a) :_a(a) {}
operator int() { return _a; }
private: int _a; };
int main() { A aa1 = 1;
int i = aa1;
return 0; }
|
文件IO
C++根据文件内容的数据格式分为二进制文件和文本文件
定义一个文件流对象
- ifstream ifile(只输入用)
- ofstream ofile(只输出用)
- fstream iofile(既输入又输出用)
看一个例子:
1 2 3 4 5 6 7 8 9 10 11 12
| int main() { ifstream ifs("test.cpp"); char ch = ifs.get();
while (ifs) { cout << ch; ch = ifs.get(); } return 0; }
|
这段程序可以读取当前文件的内容
C++特有的优点:
对内置的类型
![](https://cdn.jsdelivr.net/gh/atongrun/ImageHost@main/202301151927497.png)
对自定义的类型:
![](https://cdn.jsdelivr.net/gh/atongrun/ImageHost@main/202301151934569.png)
![](https://cdn.jsdelivr.net/gh/atongrun/ImageHost@main/202301151935531.png)
前题是自定义的类型支持流提取,这样对自定义类型的读写通过流的方式就非常的方便了。
两种读写方式对比
- 二进制读写:在内存如何存储,就如何写到磁盘文件
优点:快
缺点:写出去内容看不见
- 文本读写:对象数据序列化字符串写出来,读回来也是字符串,反序列化转成对象数据
优点:可以看见写出去是什么
缺点:存在一个转换过程,要慢一些
二进制读写
一个关于二进制读取string类型的坑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| struct ServerInfo { string _address; int _port;
Date _date; };
struct ConfigManager { public: ConfigManager(const char* filename = "server.config") :_filename(filename) {}
void WriteBin(const ServerInfo& info) { ofstream ofs(_filename, ios_base::out | ios_base::binary); ofs.write((char*)&info, sizeof(info)); }
void ReadBin(ServerInfo& info) { ifstream ifs(_filename, ios_base::in | ios_base::binary); ifs.read((char*)&info, sizeof(info)); } private: string _filename; };
int main() {
ServerInfo rinfo; ConfigManager cm; cm.ReadBin(rinfo); cout << rinfo._address << endl; cout << rinfo._port << endl;
return 0; }
|
情况1、写入字符较短时
![](https://cdn.jsdelivr.net/gh/atongrun/ImageHost@main/202301152109265.png)
结果虽然读取成功,但是程序出现了问题,退出码不是0
情况2、写入字符串较长时
![](https://cdn.jsdelivr.net/gh/atongrun/ImageHost@main/202301152111415.png)
可以看到address直接读取报错
![](https://cdn.jsdelivr.net/gh/atongrun/ImageHost@main/202301152116889.png)
原因是当address比较长的时候,string对象,字符串会存在堆里面,ptr指针指向这个字符串,但是写到文件里面的时候,写的不是堆的内存,而是ptr这个地址。
二进制读写,不大适合有在堆上申请数据类型的
文本读写
下边是文本读写的方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
|
void WriteText(const ServerInfo& info) { ofstream ofs(_filename, ios_base::out); ofs << info._address << endl; ofs << info._port << endl; ofs << info._date << endl; }
void ReadText(ServerInfo& info) { ifstream ifs(_filename, ios_base::in | ios_base::binary); ifs >> info._address >> info._port >> info._date; }
|
stringstream
一个例子:
![](https://cdn.jsdelivr.net/gh/atongrun/ImageHost@main/202301152147060.png)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| struct ChatInfo { string _name; int _id; Date _date; string _msg; };
int main() { ChatInfo winfo = { "张三", 135246, { 2022, 4, 10 }, "晚上一起看电影吧" }; stringstream oss; oss << winfo._name << endl; oss << winfo._id << endl; oss << winfo._date << endl; oss << winfo._msg << endl;
string str = oss.str(); cout << str << endl;
ChatInfo rInfo; stringstream iss(str); iss >> rInfo._name; iss >> rInfo._id; iss >> rInfo._date; iss >> rInfo._msg;
cout << "----------------------------------" << endl; cout << rInfo._date << endl; cout << rInfo._name << "[" << rInfo._id << "]:>" << rInfo._msg << endl; cout << "----------------------------------" << endl;
return 0; }
|
分割字符串:
1 2 3 4 5 6 7 8 9 10
| int main() { stringstream ss("sad ad fsd"); string s; while (ss >> s) { cout << s << endl; } return 0; }
|