c++Primer第五版第279页
IO类不能被赋值或者拷贝
由于不能被拷贝,所以形参也不可以被设置成IO类,而只能设置成IO类的引用,读写一个IO类通常会改变其状态,因此返回和传递的不能是const的
c++Primer第五版 第280页
IO类错误
strm::iostate strm是一种IO类型
一个流一旦发生错误,其上后续的IO操作都会失败。因此在使用流之前,都会先检查流的状态
将流作为条件使用,只能告诉我们流是否正常。而有时候我们需要知道流为什么失败
IO库定义了一个与机器无关的iostate类型,表述了流的完整状态,该类型可以作为一个位集合来使用
badbit表示系统级错误,如不可恢复的读写错误。在发生可恢复错误时,通常用failbit置位
到达文件末尾时,eofbit和failbit被置位。
goodbit为0,代表没有发生错误
badbit/failbit/eofbit任意一个被置位,流检测都会失败
//记住Cin的当前状态
auto old_state = cin.rdstate();//流对象的rdstate返回一个当前状态
cin.clear();//clear重置流的状态
process_input(cin);
cin.setstate(old_state);//setstate设置相应位置位
//clear还有一个接受参数的版本c
//复位failbit和badbit,保持其他标志位不变
//按位取反 faibit位为0,其余位1;按位与就可将failbit复位
cin.clear(cin.rdstate() & ~cin.failbit & ~cin.badbit);
c++Primer 第五版 第281页 管理输出缓冲
由于写操作可能很耗时,允许操作系统将多个输出操作组合位单一的设备写操作可以得到很大的性能提升
导致缓冲刷新(即数据真正写到流中)的操作有很多
- 程序正常结束
- 缓冲区满 需要刷新缓冲
- 操纵符如endl来显示刷新缓冲区
- 每个输出操作之后,我们可以用操纵符unitbuf来设置流的内部状态,用于刷新缓冲区。默认情况下,对cerr是设置unitbuf的,所以cerr是立即刷新的
- 一个输出流可能被关联到另一个流。当读写到关联的流时,被关联的流的缓冲区会被刷新。例如,默认情况下,cin和cerr都关联到cout,所以读cin和写cerr都会导致cout被刷新
除了endl,flush会直接刷新缓冲区,ends会插入一个空字符然后刷新缓冲区
cout<< unitbuf; //所有输入立即刷新,无缓冲
cout << nounitbuf;// 恢复原始缓冲设置
注意 如果程序异常终止,输出缓冲区是不会被刷新的,他的输出数据很可能停留在输出缓冲区等待打印
当调试一个已经崩溃的程序时,需要确定你认为已经输出的数据已经刷新了。否则会把大量时间浪费在追踪程序未执行上,而实际上只是程序执行了没有刷新缓冲区而已。
c++Primer 第五版 第285页 自动构造和析构
当一个fstream离开其作用域时,其关联的文件自动关闭
当一个fstream被销毁时,close被自动调用
c++Primer 第五版 第286页 文件模式
每个文件都有一个关联的文件模式用于指导如何使用文件,指定文件模式有如下限制:
- 只能对ofstream和fstream对象设置out,即写方式
- 只能对ifstream和fstream设置in,即读方式
- 只有当out也被设定时,才可以设定trunc,即截断文件
- 只要trunc没被设定,就可以设置app(即append),即每次写操作前都定位到文件末尾;app下,文件也以写模式打开
- 默认情况下,即使没有设置trunc,out模式的文件也默认会截断。为了保留以out模式打开的文件,我们必须同时指定app,这样数据才会输出到文件结尾;或者同时指定in,对文件进行读写
- ate(打开文件后立即定位到文件末尾)和binary(以二进制进行io)模式适用于任何文件流对象,可以和任何模式组合使用
以out模式打开文件会丢弃原有数据,阻止清空原有文件的方式是增加app模式
ofstream out("file1");//隐含的以out打开并截断
ofstream out("file1",ofstream::out | ofstream::trunc);
//为保留文件内容 必须指定app
ofstream out("file1",ofstream::app);
ofstream out("file1",ofstream::app | ofstream::out);
c++Primer 第五版 第283页 istringstream
当我们的某些工作是处理整行文本,而其他一些工作则是处理行中的单个单词时,通常可以使用istringstream
//定义一个简单类来描述 一个人有名字和很多号码
struct PersonInfo{ //struct 用于都是public成员
string name;
vector<string> phones;
};
//程序会读取文件 然后生成一个personinfo的vector
string line,word
vector<PersonInfo> people;
//逐行读取
while(getline(cin,line))
{
PersonInfo person;
istringstream record(line);//将记录绑定到刚读取的行
record >> person.name;//先把name读出来
while(record>>word)//一个个读取电话号码
person.phones.push_back(word);
people.push_back(person);//追加person
}
c++Primer 第五版 第289页 ostringstream
对于刚刚的例子,我们希望将其输出到新文件中,并且去除无效号码
我们可以在验证完所有号码后再将其输出
for(const auto &entry:people){
ostringstream formatted, badNums;
for(const auto &nums:entry.phones){
if (!valid(nums))
badNums << " " << nums;//将数以字符串形式存入
else
formatted << " " << format(nums);
}
if(badNums.str().empty()){
os << entry.name << " "
<< formatted.str()<<endl;
}else
cerr << badNums.str()<<endl;
}
作者说:程序最有趣的部分是对formatted和badNums的使用,使用标准的输出运算符(<<)对其进行写操作,实际上转换为string操作,分别向formatted和badNums中的string添加字符
当然我没有发现有多么有趣。。