ostream/istream 更好的支持自定义类型对象的流插入和流提取,自定义类型,可以自己重载,控制流提取和流插入的方式
cin >> str;
year = stoi(str.substr(0, 4));
mon = stoi(str.substr(4, 2));
day = stoi(str.substr(6, 2));
ctrl+z+换行结束输入
为什么可以用上边循环的写法呢?是因为cin的对象可以隐式类型转换成bool(调用operator bool),在流里面读到错误或者结束标志的时候,会返回false
举例详解:
class A
{
public:
A(int a) //这里前边加上explict,下边 A aa1 = 1 代码就编不过去了
:_a(a)
{}
operator int() //如果这个前边加explict那么int i = aa1也不行,但是可以强转
{
return _a;
}
private:
int _a;
};
int main()
{
// 内置类型 转换成自定义类型
A aa1 = 1; // 隐式类型转换 用1构造A临时对象,再拷贝构造aa1,优化后直接1构造aa1
// 自定义类型 转换成内置类型
int i = aa1;
return 0;
}
C++根据文件内容的数据格式分为二进制文件和文本文件
定义一个文件流对象
看一个例子:
int main()
{
ifstream ifs("test.cpp");
char ch = ifs.get();
while (ifs)
{
cout << ch;
ch = ifs.get();
}
return 0;
}
这段程序可以读取当前文件的内容
C++特有的优点:
对内置的类型
对自定义的类型:
前题是自定义的类型支持流提取,这样对自定义类型的读写通过流的方式就非常的方便了。
两种读写方式对比
一个关于二进制读取string类型的坑
struct ServerInfo
{
//char _address[32];
string _address; // 换成string 类型
int _port; // 100
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 winfo = { "127.0.0.1", 888 };
//ServerInfo winfo = { "https://legacy.cplusplus.com/reference/istream/istream/read/", 888 };
//ConfigManager cm;
//cm.WriteBin(winfo);
// 二进制的读
ServerInfo rinfo;
ConfigManager cm;
cm.ReadBin(rinfo);
cout << rinfo._address << endl;
cout << rinfo._port << endl;
return 0;
}
情况1、写入字符较短时
结果虽然读取成功,但是程序出现了问题,退出码不是0
情况2、写入字符串较长时
可以看到address直接读取报错
原因是当address比较长的时候,string对象,字符串会存在堆里面,ptr指针指向这个字符串,但是写到文件里面的时候,写的不是堆的内存,而是ptr这个地址。
二进制读写,不大适合有在堆上申请数据类型的
下边是文本读写的方式:
/*void WriteText(const ServerInfo& info)
{
ofstream ofs(_filename, ios_base::out);
ofs.write(info._address.c_str(), info._address.size());
ofs.put('\n');
const string str = to_string(info._port);
ofs.write(str.c_str(), str.size());
}
void ReadText(ServerInfo& info)
{
ifstream ifs(_filename, ios_base::in | ios_base::binary);
char buff[128];
ifs.getline(buff, 128);
info._address = buff;
ifs.getline(buff, 128);
info._port = stoi(buff);
}*/
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;
}
一个例子:
struct ChatInfo
{
string _name; // 名字
int _id; // id
Date _date; // 时间
string _msg; // 聊天信息
};
int main()
{
// 序列化
ChatInfo winfo = { "张三", 135246, { 2022, 4, 10 }, "晚上一起看电影吧" };
//ostringstream oss;
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;
// 网络传输str,另一端接收到了字符串串信息数据
// 反序列化
ChatInfo rInfo;
//istringstream iss(str);
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;
}
分割字符串:
int main()
{
stringstream ss("sad ad fsd");
string s;
while (ss >> s)
{
cout << s << endl;
}
return 0;
}