8.1 IO类
-
iostream读写流,fstream读写文件,sstream读写内存string对象
-
宽字符(wchar_t)支持:宽字符版本的类型和函数以w开始,例如wcin,wcout,werr,头文件在wiostream中
-
继承关系:如ifstream,istringfstream都继承于istream
8.1.1 IO对象无拷贝或复制
- 不能拷贝或对IO对象赋值
- 因此不能把形参或者返回类型设置为流类型; 通常通过引用方式传递和返回流。
- 因为读写流会改变流对象的状态,因此传递和返回的流也不能是const的
8.1.2 条件状态
- 一个流一旦发生错误,其后续IO操作都会失败
- 确定流状态的最好的方法:
while(cin >> word){
//流状态正常会执行
}
- 查询流的状态
IO库中定义了和机器无关的iostate类型,可以使用iostate类型的badbit、failbit、eofbit、goodbit来判断流的状态。- badbit:系统级错误,如不可恢复的读写错误 ;badbit置位后,流不可用;
- failbit:可恢复的错误,如期望得到数值但得到字符;failbit置位后,修正流的状态,流可以继续使用
- eofbit:文件结束后,eofbit和failbit同时置位。
- goodbit:流无错误
- 若badbit、failbit、eofbit有一个置位,检测流的状态都会返回false
- 管理条件状态
流有以下成员函数来管理流的状态rdstate()
:返回一个iostate类型值,对应流现在状态setstate()
:将给定条件置位clear(
):不接受参数版本,清除所有错误标志位,执行clear()后,流可用;带参数版本,效果和setstate相同。
auto old_state = cin.rdstate();//保存旧状态
cin.clear();//使cin有效
process_input(cin);//使用cin
cin.setstate(old_state );//将cin恢复到原来状态
//复位failbit和badbit,其他位不变
cin.clear(cin.rdstate() &~cin.failbit &~cin.badbit);
8.1.3 管理输出缓冲
- 缓冲刷新后,数据从缓冲区打印出或写到磁盘,不保存在内存中;导致缓冲刷新的原因有:
- 程序结束,main函数return
- 缓冲区满
- 调用endl等操作符
- 使用操作符unitbuf设置流的内部状态;默认情况下,cerr设置了unitbuf,写道cerr中的内容立即执行
- 一个流可以关联另外一个流;读写被关联流时,关联到的流的缓冲区会被刷新
- unitbuf操作符
- 设置
unitbuf
后,每次读写操作后都进行一次flush - 设置
nounitbuf
后,使用正常系统管理的缓冲区刷新机制 - 警告:程序崩溃,输出缓冲区不会被刷新;这时输出数据被挂起,想不到这茬,容易debug没思路
- 设置
- 关联输入和输出流
- note:交互式系统通常应该关联输入流和输出流;这意味着所有输出,包括用户的提示信息,都会在读操作之前打印出来
- 使用
tie
可以关联输入输出流 - 不带参数版本:关联到输出流,返回该输出流指针;未关联到流,返回空指针
- 带ostream指针参数,将自己关联到该ostream
cin.tie(&cout); //将cin和cout关联在一起
ostream *old_tie =cin.tie(nullptr); //cin不关联任何流,并返回原来关联的流的指针
cin.tie(&cerr); //读取cin会刷新cerr
cin.tie(&old_tie) //重建cin和原关联流的联系
8.2 文件输入输出
8.2.1 使用文件流对象
- 创建文件流对象,若提供文件名,
open
自动调用 - 成员函数open和close
- 空的文件流对象可以使用open函数和文件关联起来
- 对一个已经和文件关联的流调用open,failbit会置位;若想关联到其他文件,要先调用close。
- 调用open失败,failbit会被置位;调用open后检查是否调用成功
fstream out;
out.open("a.txt");
if(out){
//文件操作
}
- 自动构造和析构
fstream被销毁时,会自动调用close函数
8.2.2 文件模式
- 文件模式限制
- out:对ofstream和fstream使用
- in:对ifstream和fstream使用
- trunc:只有设置为out模式后,才能设置为trunc
- app:没设置trunc才可以设置app模式;app模式下,默认是out模式
- 默认情况下out模式打开的文件,即使没指定trunc,文件也是截断的;要保留用out模式打开的文件,应该设app模式,数据被追加到文件尾;同时设置in模式,就可以同时对文件进行读写操作
- ate和binary可以对任何类型摁键流对象使用,和任意模式组合
- 以out模式打开 文件会丢弃已有数据;阻止该行为的方法是设置app或者in模式
//文件被截断
ofstream out("file");//隐含截断
ofstream outs("file",ofstream::out);//隐含截断
ofstream outs("file",ofstream::out|ofstream::trunc);//显式截断
//文件被保留
ofstream outs("file",ofstream::app);
ofstream //显式保留outs("file",ofstream::out|ofstream::app);//显式保留
- 每次调用open时,都会确定文件模式
8.3 string流
8.3.1 使用istringstream
- 对整行文件进行处理,其他工作处理单词时,使用
istringstream
很方便
例子:文件原格式为姓名+若干电话:
乔纳森 138XXXXXXXXXX 138XXXXXXXXXX
乔瑟夫 138XXXXXXXXXX
空条承太郎 138XXXXXXXXXX
东方仗助 138XXXXXXXXXX 138XXXXXXXXXX
空条徐伦 138XXXXXXXXXX 138XXXXXXXXXX 138XXXXXXXXXX
strcut JOJO{
string name;
vector<string> phones;
};
string line,phone;
vector<JOJO> jojos;
while(getline(cin,line)){
JOJO jojo;
//note:如果是在while外声明istringstream 很容易错,见练习8.11
//istringstream 声明在while外,这里使用record.str(line)
//但是record的failbit和badbit是置位的,需要record.clear()
istringstream record(line);
record >>jojo.name;
while(record>>phone){
jojo.phones.push_back(phone);
}
jojos.push_back(jojo);
}
8.3.2 使用ostingstream
- 在逐步构造希望最后一起打印时,ostingstream很有用。
使用过程中可以把ostingstream
当成一个没有大小显示的缓存区使用,最后要获取ostingstream
中内容,使用ostingstream::str()
。