在C语言中,我们使用最频繁的输入输出方式为: scanf 和 printf.
流的特征为: 有序连续,具有方向性.
C++系统实现了一个庞大的类库,其中ios为基类,其他类都是直接或者间接继承自ios类.
C++标准库提供了4个全局流对象(cin、cout、cerr、clog).
注意:
int main()
{
int a , b;
cin >> a; //向放缓冲区中输入 1 , 2
cout << a << endl;
cin >> b; //直接从输入缓冲区提取2,不用认为输入
cout << b << endl;
return 0;
}
2.输入的数据类型必须与要提取的数据类型一致.
3.回车和空格都可以作为数据之间的分隔符,所以多个数据可以在一行输入,也可以分行输入.但是如果是字符型和字符串,则空格无法用cin输入,字符串中也不能有空格.回车键也无法读入.
int main()
{
string s;
cin >> s; //输入:"hello yzh"
cout << s << endl; //输出:"hello"
return 0;
}
对于含有空格的字符串,我们可以尝试采用getline函数进行读取,因为getline函数只有遇到’\n’才会停止读取.
int main()
{
string s;
getline(cin, s); //输入: "hello yzh";
cout << s << endl; //输出:"hello yzh
return 0;
}
4:对于内置类型,cin和cout可以直接输入和输出相关数据,原因:标准库已经将所有内置类型的输入和输出全部重载了,
流插入: >>
流提取: <<
5:对于自定义类型,如果要支持cin和cout的标准输入输出,需要对<<和>>进行重载.
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;
}
int main()
{
Date de;
cin >> de; //2023 7 6
cout << de; //2023 7 6
return 0;
}
6: 在线OJ中的输入和输出.
例如: C语言中的cin和C++中的scanf默认都是用空格和换行分割的.
输入格式:2023 07 06
int main()
{
int year, month, day;
cin >> year >> month >> day; // 2023 07 06
scanf("%d%d%d", &year, &month, &day); // 2023 07 06
return 0;
}
输入格式:20230706
要达到输入格式C语言可以利用sancf中规定年为4个位置,月为2个位置,日为2个位置.
int main()
{
int year, month, day;
scanf("%4d%2d%2d", &year, &month, &day); //输入格式:20230706
return 0;
}
C++只能通过stoi函数将数字字符串按照年,月,日的格式进行分割,然后将数字字符串格式转换为整数.
int main()
{
int year, month, day;
string str;
cin >> str;
year = stoi(str.substr(0, 4));
month = stoi(str. substr(4, 2));
day = stoi(str.substr(6, 2));
cout << year << "年" << month << "月" << day<<"日";
}
并且,C++中还可以通过while循环支持多行测试用例,当然,我们可以使用ctrl+z+换行给一个流读取结束的标志.
int main()
{
int year, month, day;
string str;
while (cin >> str)
{
year = stoi(str.substr(0, 4));
month = stoi(str.substr(4, 2));
day = stoi(str.substr(6, 2));
cout << year << "年" << month << "月" << day<<"日";
}
return 0;
}
二进制读写; 在内存中如何存储,就如何写到磁盘文件上.
文本读写: 序列化成字符串写出来,读回来也是字符串,
C++根据文件内容的数据格式分为二进制文件和文本文件。采用文件流对象操作文件的一般步骤.
2.使用文件流对象的成员函数打开一个磁盘文件,使的文件流对象和磁盘文件之间建立联系.( 输入或者输出).
3.利用提取和插入运算符对文件进行读写操作,或者使用成员函数进行读写.
以下为C++IO流文本读,写以及二进制读写.
struct ServerInfo
{
//char _address[32]; //用于二进制读写,必须采用字符数组,不能采用string类.
string _address; //用于文本读写,可以采用string类.
int _port;
};
class ConfigManager
{
public:
ConfigManager(const char* filename = "sever.config")
:_filename(filename)
{}
//二进制写:将数据写道文件里面.
void WriteBin(ServerInfo& info)
{
ofstream ofs(_filename, ios_base::out | ios_base::binary); //以二进制覆盖写的方式打开文件.
ofs.write((const char*)&info, sizeof(info)); //将目标大小的数据写入.
}
//二进制读,将文件里面的数据读取到内存中.
void ReadBin(const ServerInfo& info)
{
ifstream ifs(_filename, ios_base::in | ios_base::binary);//以二进制读的方式打开文件.
ifs.read((char*)&info, sizeof(info)); //将目标大小的数据读取.
}
//文本读(输入到内存中)
void ReadText1(ServerInfo& info)
{
ifstream ifs(_filename, ios_base::in);
ifs >> info._address >> info._port;
}
//文本写(输出到文件中)
void WriteText1(ServerInfo& info)
{
ofstream ofs(_filename, ios_base::out);
ofs << info._address << endl;
ofs << info._port << endl;
}
private:
string _filename; //配置文件.
};
测试案例如下:
int main() {
//写入数据(二进制)
ServerInfo winfo = { "127.0.0.1",888 };
ConfigManager cm;
cm.WriteBin(winfo);
//读取数据(二进制)
/*ServerInfo rinfo;
ConfigManager cm;
cm.ReadBin(rinfo);
cout << rinfo._address << endl; //打印
cout << rinfo._port << endl;*/
//文本写.
//ServerInfo winfo = { "127.0.0.1",888};
//ConfigManager cm;
//cm.WriteText1(winfo);
//文本读.
//ServerInfo rinfo;
//ConfigManager cm;
//cm.ReadText1(rinfo);
//cout << rinfo._address << endl;
//cout << rinfo._port << endl;
return 0;
}
注意:
二进制读,写的自己实现
对文本读来说,我们可以调用ifstream类对象中的成员函数读取文本数据,这一过程也成为输入,步骤如下:
void ReadText( ServerInfo& info)
{
ifstream ifs(_filename, ios_base::in | ios_base::binary);
char buff[128];
ifs.getline(buff, 128); //1
info._address = buff; //将读取的数据放在对应的变量中.
ifs.getline(buff, 128); //2
info._port = stoi(buff);//将读取的数据转回整型变量中.
}
对于文本写来说,我们也可ofstream类对象中的成员函数将数据写入文件中,这一过程也成为输出.步骤如下:
void WriteText(const ServerInfo& info)
{
ofstream ofs(_filename, ios_base::out | ios_base::binary);
ofs.write(info._address.c_str(), info._address.size()); //1
ofs.put('\n'); //'n'分割数据,读取时方便分辨.
const string str = to_string(info._port);//2
ofs.write(str.c_str(), str.size());
}
利用istream类对象中的get()函数读取Test.cpp文件中的数据(输入),然后再利用cout将打印出来.
int main()
{
ifstream ifs("Test.cpp");
char ch = ifs.get();
while (ifs)
{
cout << ch;
ch = ifs.get();
}
return 0;
}
在C++中,我们可以使用stringstream来将整型变量的数据达转换为字符串形式.主要有两种使用方式:
1.将数值数据格式转化为字符串.
int main()
{
//方法一:
int a = 10;
string sa;
stringstream s;
s << a; //将int类型的a放入输入流
s >> sa; //从s中抽取前面插入的int类型的值,赋值给string类型
cout << sa << endl;
//方法二:
s.str(""); //将stringstream底层管理的string对象设置为""。
s.clear(); //将上次转换状态清空掉
//进行下一次转换
double b = 3.14;
s << b;
sa = s.str(); //获取stringstream中管理的string类型(方式二)
cout << sa << endl;
return 0;
}
2.字符串拼接.
int main()
{
//方法一:
string rets;
stringstream s;
s << "hello" << "yzh"; //将多个字符串放入stringstream中
s >> rets;
cout << rets << endl;
//方法二:
s.str(""); //将stringstream底层管理的string对象设置为空字符串
s.clear(); //将上次转换状态改变.
s << "welcome" << " " << "to" << " " << "C++"; //将多个字符串放入stringstream中
rets = s.str();
cout << rets << endl;
return 0;
}
3.序列化和反序列化结构数据,将结构体多个内置类型数据转换为字符串类型.当然,如果自定义类型自定义写了流插入和流提取,那么便可以直接使用.
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 ChatInfo
{
string _name;
int _id;
Date _date;
string _msg;
};
int main()
{
// 结构信息序列化为字符串
ChatInfo winfo = { "张三", 135246, { 2022, 4, 10 }, "晚上一起看电影吧"
};
stringstream oss;
oss << winfo._name << " " << winfo._id << " " << winfo._date << " "
<< winfo._msg;
string str = oss.str();
cout << str << endl << endl;
// 我们通过网络这个字符串发送给对象,实际开发中,信息相对更复杂,
// 一般会选用Json、xml等方式进行更好的支持
// 字符串解析成结构信息
ChatInfo rInfo;
stringstream iss(str);
iss >> rInfo._name >> rInfo._id >> rInfo._date >> rInfo._msg;
cout << "-------------------------------------------------------"
<< endl;
cout << "姓名:" << rInfo._name << "(" << rInfo._id << ") ";
cout << rInfo._date << endl;
cout << rInfo._name << ":>" << rInfo._msg << endl;
cout << "-------------------------------------------------------"
<< endl;
return 0;
}
注意: