这次是关于IO库的内容,东西都是之前我们常常用到的东西,在我看Primer之前IO库曾经是我最喜欢的C++的东西(笑)。
这一章在书中的内容占比不大,内容相对比较少,很多东西都很常用所以看起来也不会难受。
这篇之后会歇一段时间再继续这个系列,可能会发点别的东西,该赶紧干点正事了。
8.1 IO类
- iostream,fstream,sstream是IO类的三个头文件,分别对应控制台IO,文件IO,内存IO
- 头文件中的类名都是分写入型(改i),读取型(改o),读写型(不加),还额外对应了一组为了支持宽字符wchar_t类型而设的宽字符型(加w)
- IO库的继承使得我们可以忽略流的差异,可以像使用cin一样操作其他的这么多类,只要记得一些独有的操作即可
- IO流都不能进行拷贝或赋值,形参或返回类型自然也就不能设置为IO类型,传递操作都要使用引用
- 由于对IO流的读写会改变其状态,因此传递和返回的引用也不该是const的
- IO流可能会发生一些错误,从而改变IO流的条件状态,这其中一些错误是可以修复并重置条件状态来继续此IO流的
- 流的条件状态位有[流].iostate,[流].badbit,[流].failbit,[流].eofbit,[流].goodbit
- IO可以用 [流].good() 来查询是否处于有效状态或用 [流].fail() 来查询是否出错,只有正常的流才可读写,此判断也可以通过直接使用流作为条件使用,相当于使用fail()
- 通常来说,若 [流].bad() 返回true,则流发生了不可恢复的读写错误
- [流].eof() 返回流是否读到了结束符或到达了尾部
- 可以使用 [流].clear(不带参数) 复位流的所有条件位,使其返回good
- 可以使用 [流].clear(某状态位) 复位流的指定条件位
- [流].rdstate()可以读取流的状态,格式是int
- [流].setstate()可以利用上面读取到的流状态一口气设置状态
- 每个输出流都有自己的缓冲区,又是我们需要缓冲刷新来立即输出一些数据,以下情况会立即刷新:程序正常结束,缓冲区满,endl,ends或flush操作符(附加换行,附加一个空字符,什么都不附加),设置unitbuf,读写被关联的流
- 其中unitbuf是流内部的一种状态调用函数,用nounitbuf来复位,会使得此流进入立即输出的状态,cerr就设置了这个位
- 用tie可以将两个流关联起来,详细操作在写到tuple时再看
8.2 文件输入输出
- 如前所述,操作与cin,cout等一样,很常用的函数是getline
- fstream构造时可以直接提供文件名,C11使得这个文件名可以是string也可以是C风格的字符数组
- open函数负责让空文件流对象打开文件,如果open失败,则failbit会被置位,所以open后用if检查一下是好习惯
- 对已经打开了文件的文件流用open也会导致失败损坏文件流
- 为了打开不同的文件,我们需要用close来关闭当前文件再打开
- fstream被析构时,close会自动调用不用担心
- 每个流都有自己的文件模式,此参数在构造或open时在文件名后附加,分为in(输入),out(输出),app(追加,每次写入都定位到尾部),ate(打开后定位到尾部),trunc(截断,清空当前文件内容后操作),binary(二进制模式)
- in,out如其名会默认与ifstream之类对应绑定
- 只有设定了out才可以用trunc
- 只有trunc没设定,就可以用app
- app默认就包含了out
- 默认下用out打开包含了trunc,因此为了保持out的内容,需要在指定out的同时指定app或指定in,方法是对应该ofstream(因而默认有out)指定为app或者用“或|”符号
8.3 string流
- string流的构造参数是一个string,用str()函数可以返回其里面的string的拷贝,如果是str(string s),则会将s拷贝进去返回void
- 用getline配合其第二个参数很方便地进行逐行读取
- 当流中的string全部读完也会触发eof
- 行分析读取的常用写法: