C++语言不直接处理输入输出,而是通过一族定义在标准库中的类型来处理IO。
这些类型支持从设备读取数据、向设备写入数据的IO操作,设备可以是文件、控制台窗口等
还有一些允许内存IO,即从string读取数据,向string写入数据。
1.IO类
查询流的状态:
管理条件状态:
流对象的rdstate成员返回一个iostate值,对应流的当前状态。setstate操作将给定条件位置位,表示发生了对应错误。
clear成员是一个重载的成员:一个不接受参数,一个接受一个iostate类型的参数。
clear不接受参数的版本清楚(复位)所有错误标志位。执行clear()后,调用good会返回true.
举例使用这些成员:
auto old_state = cin.rdstate(); //记住cin的当前状态
cin.clear(); //使cin有效
process_input(cin); //使用cin
cin.setstate(old_state); //将cin置为原有状态
带参数的clear版本接受一个iostate值,表示流的新状态。为了复位单一条件状态位,我们首先用rdstate读出当前条件
状态,然后用位操作将所需位复位来生成新的状态。例如:下面代码复位failbit和badbit,eofbit不变。
cin.clear(cin.rdstate() & ~cin.failbit & ~cin.badbit);
管理输出缓冲:
导致缓冲刷新的原因:
1.程序正常结束,作为main函数的return操作的一部分,缓冲刷新被执行。
2.缓冲区满时,需要刷新缓冲,而后新的数据才能写入缓冲区。
3.在每个输出操作之后,我们可以用操作符unitbuf设置流的内部状态,来清空缓冲区。默认情况下,对cerr是设置unitbuf的,
因此写到cerr的内容都是立即刷新的。
4.一个输出流可能被关联到另一个流。在这种情况下,当读写被关联的流时,关联到的流的缓冲区会被刷新。例如,默认情况下
cin和cerr都关联到cout。因此读cin或写cerr都会导致cout的缓冲区被刷新。
刷新缓冲区:
cout<<"hi"<<endl; //endl:完成换行并刷新缓冲区
cout<<"hi"<<flush; //flush:只是刷新缓冲区
cout<<"hi"<<ends; //ends:输出一个空字符,然后刷新缓冲区
cout<<unitbuf; //之后的所有输出操作都会立即刷新缓冲区
//任何输出都立即刷新,无缓冲
cout<<nounitbuf; //回到正常的缓冲方式
注意:如果程序崩溃,输出缓冲区不会被刷新。
要确认那些你认为已经输出的数据确实已经刷新了。
关联输入和输出流:
tie无参版本,返回指向输出流的指针。如果本对象当前关联到一个输出流,则返回的就是指向这个流的指针,如果对象
未关联到流,则返回空指针。
tie第二个版本接受一个指向ostream的指针,将自己关联到此ostream。即,x.tie(&o)将x关联到输出流o。
举例:可以将istream或ostream对象关联到ostream。
cin.tie(&cout) //仅仅用来展示:标准库将cin和cout关联在一起
ostream* old_tie = cin.tie(nullptr); //cin不再与其他流关联
cin.tie(&cerr); //读取cin会刷新cerr
cin.tie(old_tie); //重建cin和cout间的正常关联
2.文件输入输出
文件操作类型:
ifstream:读文件
ofstream:写文件
fstream:读写文件,继承自iostream
使用文件流对象
举例:
1.读取整个文件
string path = "C:\\Users\\Administrator\\Desktop\\abc1.txt";
string content;
ifstream ifs(path);
ifs>> content;
ifs.close();
2.读取文件的每一行
string path2 = "C:\\Users\\Administrator\\Desktop\\abc2.txt";
string line;
ifstream ifs;
ifs.open(path2);
while(getline(ifs,line))
{cout<<line<<endl;}
ifs.close();
如果open失败,failbit会被置位,因为调用open可能失败,进行open是否成功的检测通常是一个好习惯。
ofstream out;
out.open(path);
if(out) //检测open是否成功
对一个已经打开的文件流调用open会失败,并会导致failbit被置位。
为了将文件流关联到另外一个文件,必须首先关闭已经关联的文件。
如果open成功,则open会设置流的状态,使得good()为true。
当一个fstream对象离开其作用域时,与之关联的文件会自动关闭。
当一个fstream对象被销毁时,close会自动被调用。
*****文件模式*****
in: 以读方式打开
out: 以写方式打开
app: 每次写操作前均定位到文件末尾
ate: 打开文件后立即定位到文件末尾
trunc: 截断文件
binary: 以二进制方式进行IO
以out模式打开文件会丢弃已有数据
默认情况下,打开一个ofstream时,文件的内容会被丢弃,阻止ofstream清空文件内容是同时指定app模式。
举例:
1.创建文件、清空文件内容
ofstream out(path); //默认out模式
ofstream out(path,ofstream::out);
2.追加文件内容
ofstream out; //默认out模式
out.open(path,ofstream::out | ofstream::app);
out<<"abc";
out.close();
3.string流
stringIO操作类型:
istringstream: 从string读取数据
ostringstream: 向string写入数据
stringstream: 读写都可以,继承自iostream
stringstream特有的操作:
sstream strm; //strm是一个未绑定的stringstream对象
sstream strm(s); //strm保存string s的一个拷贝,构造函数时explicit的
strm.str(); //返回strm所保存的string的拷贝
strm.str(s); //将string s拷贝到strm中,返回void
*****使用istringstream和ostringstream*****
struct PersonInfo
{
string name;
vector<string> phones;
};
string path = "C:\\Users\\Administrator\\Desktop\\abc1.txt";
ifstream ii(path);
string line, word;
vector<PersonInfo> people;
while (getline(ii, line)) //从文件中读取每一行
{
PersonInfo info;
istringstream record(line); //处理每一行string
record >> info.name; //第一个是名字
while (record >> word) //后面的是电话
info.phones.push_back(word);
people.push_back(info);
}
//打印
ostringstream out;
for (const auto& entry : people)
{
out << "name:" << entry.name;
for (const auto& nums : entry.phones)
{ out<< " " << nums;}
out<< " ";
}
cout << out.str() << fflush; //输出