文章目录
一、标准IO流
C++系统实现了一个庞大的类库,其中ios为基类,其他类都是直接或间接派生自ios类。
C++标准库提供了4个全局流对象cin、cout、cerr、clog,使用cout进行标准输出,即数据从内存流向控制台(显示器)。使用cin进行标准输入即数据通过键盘输入到程序中,同时C++标准库还提供了cerr用来进行标准错误的输出,以及clog进行日志的输出,从上图可以看出,cout、cerr、clog是ostream类的三个不同的对象,因此这三个对象现在基本没有区别,只是应用场景不同。
注意点:
- cin为缓冲流。键盘输入的数据保存在缓冲区中,当要提取时,是从缓冲区中拿。如果一次输入过多,会留在那儿慢慢用,如果输入错了,必须在回车之前修改,如果回车键按下就无法挽回了。只有把输入缓冲区中的数据取完后,才要求输入新的数据。
- 输入的数据类型必须与要提取的数据类型一致,否则出错。出错只是在流的状态字state中对应位置位(置1),程序继续。
- 空格和回车都可以作为数据之间的分格符,所以多个数据可以在一行输入,也可以分行输入。但如果是字符型和字符串,则空格(ASCII码为32)无法用cin输入,字符串中也不能有空格。回车符也无法读入。
- cin和cout可以直接输入和输出内置类型数据,原因:标准库已经将所有内置类型的输入和输出全部重载了
- 对于自定义类型,如果要支持cin和cout的标准输入输出,需要对<<和>>进行重载。
二、文件IO流
对文件的输入和输出和使用cout和cin类似,把读入的键盘和输出的显示器转换为文件即可。
2.1 文件读写方式
C++根据文件内容的数据格式分为二进制文件和文本文件。采用文件流对象操作文件的一般步骤:
- 定义一个文件流对象
类 | 作用范围 |
---|---|
ifstream ifile | 输入用 |
ofstream ofile | 输出用 |
fstream iofile | 输入或输出用 |
- 使用文件流对象的成员函数打开一个磁盘文件,使得文件流对象和磁盘文件之间建立联系
打开方式 | 功能 |
---|---|
in (input) | 以读的方式打开文件 |
out (output) | 以写的方式打开文件 |
binary (binary) | 以二进制方式对文件进行操作 |
ate (at end) | 输出位置从文件的末尾开始 |
app (append) | 以追加的方式对文件进行写入 |
trunc (truncate) | 先将文件内容清空再打开文件 |
- 使用提取和插入运算符对文件进行读写操作,或使用成员函数进行读写
成员函数 | 功能 |
---|---|
put | 插入一个字符到文件 |
write | 插入一段字符到文件 |
get | 从文件提取字符 |
read | 从文件提取多个字符 |
tellg | 获取当前字符在文件当中的位置 |
seekg | 设置对文件进行操作的位置 |
>>运算符重载 | 将数据形象地以“流”的形式进行输入 |
<<运算符重载 | 将数据形象地以“流”的形式进行输出 |
- 关闭文件 ,类的成员函数close()
对数据的读取和写入
void test1()
{
ofstream ofs("./test.txt", ofstream::out);//以写的方式打开,也可不写默认也是这种方式
//也可以这样打开
//ofstream ofs;
//ofs.open("./test.txt", ofstream::out)
person ps;
ofs << ps.name << " " << ps.id << " " << ps.age;//写入空格区分,方便读取
ofs.close();
}
//如果要使用多种打开方式可以使用或位运算符,因为每一种打开方式只占一个权值
ofstream ofs("./test.txt", ofstream::out|ofstream::app);
void test2()
{
ifstream ifs("./test.txt", ifstream::in);
person ps;
ifs >> ps.name >> ps.id >> ps.age;
ifs.close();
cout << ps.name << " " << ps.id << " " << ps.age << endl;
}
2.2 实现对自定义类的输入和输出
#include<iostream>
#include<string>
#include<fstream>
using namespace std;
class Date
{
friend ifstream& operator>>(ifstream& ifs, Date& date);
friend ofstream& operator<<(ofstream& ofs, const Date& date);
friend ostream& operator<<(ostream& os, const Date& date);
public:
Date(int _year = 2000, int _month = 1, int _day = 1)
:year(_year), month(_month), day(_day)
{}
private:
int year;
int month;
int day;
};
ostream& operator<<(ostream& os, const Date& date)
{
os << date.year << "-" << date.month << "-" << date.day << '\n';
return os;
}
ofstream& operator<<(ofstream& ofs, const Date& date)
{
//ofs接收字符或字符串开始,这里是一个空串,如果直接写入整型会匹配出错
ofs << "" << date.year << " " << date.month << " " << date.day << '\n';
return ofs;
}
ifstream& operator>>(ifstream& ifs, Date& date)
{
ifs >> date.year >> date.month >> date.day;
return ifs;
}
int main()
{
/*Date d1;
Date d2(2022, 4, 6);
ofstream ofs("./test.txt", ofstream::out);
ofs << d1 << d2;*/
Date d3;
Date d4;
ifstream ifs("./test.txt");
ifs >> d3 >> d4;
cout << d3 << d4;
return 0;
}
三、stringstream流
在程序中如果想要使用stringstream,必须要包含头文件<sstream>。在该头文件下,标准库三个类:istringstream、ostringstream 和 stringstream,分别用来进行流的输入、输出和输入输出操作,本文主要介绍stringstream。
3.1 将数值类型数据格式化为字符串
void test1()
{
int a = 123456789;
string sa;
stringstream s;
s << a;
s >> sa;
cout << sa << endl;
//s.clear();//不使用的话不能再读入
double d = 3.14159;
s << d;
s >> sa;
cout << sa << endl;;
}
两个输出相同
使用clear()函数后
来分析一下clear的作用
stringstream 的clear()函数
原型: void clear (iostate state = goodbit);
标志位一共有4种, goodbit, eofbit, failbit, badbit
clear可以清除掉所有的error state
原因在于, s2在第一次调用完operator<<和operator>>后,来到了end-of-file的位置,此时stringstream会为其设置一个eofbit的标记位,标记其为已经到达eof。查文档得知, 当stringstream设置了eofbit,任何读取eof的操作都会失败,同时,会设置failbit的标记位,标记为失败状态。所以后面的操作都失败了,toAdd的值一直都是1
函数str()的两种用法
- str()获得流对象里面的字符串
- str(“”)清空stringstream对象内容
3.2 字符串拼接
void test2()
{
stringstream s;
s << "first" << ",second" << ",third";
cout << s.str() << endl;
s.str("");//清空
s << "1231231";
cout << s.str() << endl;
}
clear()重置流的标志状态;str(“”)清空流的内存缓冲,重复使用内存消耗不再增加!