一、IO类
我们常用的IO对象是关联到用户的控制台窗口的(系统的默认设置,可更改)
iostream中定义了用于读写流的基本类型,fstream中定义了读写命名文件(已存在的文件)的类型,sstream中定义了读写内存中string对象的类型。每个头文件中都有专门用来读写宽字符的类型
概念上,设备类型和字符大小都不会影响我们要执行IO操作。标准库使我们能忽略这些不同类型的流之间的差异,这是通过继承机制实现的。我们通常可以将一个派生类对象当作其基类对象来使用
我们不能拷贝或对IO对象赋值,所以我们不能将形参或返回类型设置为流类型,我们一般将其设置为引用类型,又因为读写一个IO对象会改变其状态,因此该引用不是底层const的
IO操作一个与生俱来的问题是可能发生错误
- 1、iostate是一种机器相关的类型,提供了表达条件状态的完整功能
- 2、badbit用来指出流已崩溃,不可恢复的系统级错误
- 3、failbit用来指出一个IO操作失败,可恢复错误
- 4、eofbit用来指出流到达了文件结束,可恢复错误
- 5、goodbit用来指出流未处于错误状态,此值保证为零
- 6、eof()若流的eofbit置位,则返回true
- 7、fail()若eofbit或failbit置位,返回true
- 8、bad()如果badbit置位,返回true
- 9、good()若流对象处于有效状态,则返回true
- 10、clear()将流的所有条件状态位复位,将流的状态设置为有效,返回void
- 11、clear(flags)将指定的状态位复位,返回void
- 12、setstate(flags)将指定的状态位置位,返回void
- 13、rdstate()返回流的当前状态,类型是iostate
eofbit不属于fail状态也不属于good状态。亲测有效*
一个流一旦发生错误,其上后续的IO操作都会失败。只有当一个流处于无错状态时,我们才可以从它读取数据或向它写入数据。由于流可能处于错误状态,因此代码通常应该在使用一个流之前检查它是否处于良好状态。确定一个流对象的状态的最简单的方法是将它当作一个条件来使用。如果流的操作成功,则流保持有效状态
IO库定义了4个iostate类型的constexpr值表示特定的位模式。这些值用来表示特定类型的IO条件,可以与位运算符一起用来一次性检测或设置多个标志位。
如果badbit、failbit和eofbit任意一个被置位,则流的状态为失效。good()或fail()是确定流的总体状态的方法,eof()和bad()只能表示特定的错误
每个输出流都管理一个缓冲区,用来保存程序读写的数据。这有利于将IO操作和cpu进行一定程度的分离,可以提高系统的运行速度
导致缓冲区刷新的原因:程序正常结束、缓冲区满的时候、使用操纵符来显式刷新、在一个输出操作之后,我们可以使用unitbuf设置流的内部状态,来清空缓冲区、具有关联关系的流的缓冲区的刷新
cerr是设置了unitbuf的,所以其内容都是立即刷新的
flush刷新缓冲区,但不输出任何额外的字符
ends向缓冲区插入一个空字符,然后刷新缓冲区
设置了unitbuf的流会在接下来的每次操作之后都进行一次flush操作,而nounitbuf则重置流,使其恢复使用正常的系统管理的缓冲区刷新机制
如果程序崩溃,输出缓冲区不会被刷新(确保已经刷新)
标准库将cout和cin、cerr关联到一起,在进行输入或错误输出之前,所有的输出都将被打印出来(交互式系统通常应该关联输入流和输出流)
一般来说都是将istream对象或ostream对象关联到ostream对象上的。这样的话,对前一个对象的操作,会提前刷新后一个ostream对象所管理的缓冲区。与关联有关的操作是由tie函数来实现的,该函数有两个版本,有参数的那个版本返回的好像就是参数的值。我们也可以通过空指针来解关联。每个流最多关联到一个流,但多个流可以同时关联到同一个ostream
以上介绍的绝大多数知识,所有流都是通用的
二、文件输入输出
ifstream从一个给定的文件读取数据,ofstream向一个给定文件写入数据,fstream可以读写给定文件
我们在创建一个文件流对象时,可以进行文件的绑定、文件模式的指定、也可以只是创建一个单一的文件流对象。默认的文件mode依赖于文件流的类型
open(s)打开名为s的文件,并将文件与流对象进行绑定,s可以是string对象也可是指向C风格字符串的指针。返回void
close()关闭与流对象绑定的文件,返回void。好像只是关闭,并未解绑定。进行了解绑定
is_open()返回一个bool值,指出与文件流对象关联的文件是否成功打开且尚未关闭
接受一个iostream类型引用(或指针)参数的函数,可以用一个对应的fstream(或sstream)类型来调用(因为继承的原因)。动态绑定
为了将文件流关联到另一个文件,必须首先关闭已经关联的文件。一旦文件成功关闭,我们可以打开新的文件
当一个文件流对象被销毁时,close会自动被调用(关闭该流所绑定的文件并解除关联)
每一个文件流都有一个关联的文件模式,用来指出如何使用文件
- 1、in 以读的方式打开
- 2、out 以写的方式打开
- 3、app 每次写操作前均被定位到文件末尾
- 4、ate 打开文件后立即定位到文件末尾
- 5、trunc 截断文件(既丢弃已有数据)
- 6、binary 以二进制方式进行IO
无论用哪种方式打开文件,我们都可以指定文件模式(一般就两种吧)
- 1、只可以对ofstream或fstream对象设定out模式
- 2、只可以对ifstream或fstream对象设定in模式
- 3、只有当out被设定时才可以设定trunc模式。也就是说trunc也只能用于ofstream和fstream
- 4、只要trunc没被设定,就可以设定app模式。在app模式下,即使没有显式指定out模式,文件也总是以输出方式被打开的
- 5、默认情况下,即使我们没有指定trunc,以out模式打开的文件也会被截断。为了保留以out模式打开的文件的内容,我们必须同时指定app模式,这样只会将数据追加写到文件末尾;或者同时指定in模式,即打开文件既进行输入又进行输出。
- 6、ate和binary模式可用于任何类型的文件流对象,且可以与其他任何文件模式组合使用
每个文件流类型都定义了一个默认的文件模式,当我们未指定文件模式时,就使用默认模式。ifstream默认的是in,oftream默认的是out,fstream默认的是in和out
*理清各种文件模式之间的关系
注意在同时指定两种模式的时候,用|符号连接
建议在每次打开文件时,都要显示设置模式,以防出错
三、string流
sstream头文件定义了三个类型来支持内存IO。istringstream从string读取数据,ostringstream向string写入数据,stringstream可读可写
这三种类型定义的构造函数,可以将在对象中保存一个string的拷贝(你懂的)
str()函数
最后三种类型,实际使用一次就会了
四、IO库再探
除了条件状态外,每个iostream对象还维护一个格式状态来控制IO如何格式化的细节
流的格式状态*
标准库定义了一组操纵符来修改流的格式状态,一个操纵符是一个函数或一个对象,会影响流的状态,并能用作输入或输出运算符的运算对象。类似输入和输出运算符,操纵符也返回它所处理的流对象,因此我们可以在一条语句中组合操纵符和数据(在同一条语句中使用,没问题)
*这里我需要一个例子
操纵符用于两大类输出控制:控制数值的输出形式以及控制补白的数量和位置。大多数改变格式状态的操纵符都是设置/复原成对的;一个操纵符用来将格式状态设置为一个新的值,而另一个用来将其复原,恢复为正常的默认格式
当操纵符改变流的格式状态时,通常改变后的状态对所有后续IO操作都生效。通常最好在不再需要特殊格式时尽快将流恢复到默认状态
控制布尔值的格式、指定整型值的进制、在输出中显式标出进制、控制浮点数格式(打印精度、指定浮点记数法、是否打印小数点)、输出补白(精细的格式控制)、控制输入格式(是否忽略空白)
输出补白操纵符:
- 1、setw:指定下一个数字或字符串值的最小空间(读或写)
- 2、left:表示左对齐输出
- 3、right:表示右对齐输出,右对齐是默认格式
- 4、internal:控制负数的符号的位置,它左对齐符号,右对齐值,用空格填满中间的空间
- 5、setfill:允许使用一个字符代替默认的空格来补白输出
setw和endl一样,不改变输出流的内部状态。它只决定下一个输出的大小
流对象的格式状态应该不属于其内部状态
setbase(b)将整数输出为b进制
操作符hex、oct和dec只影响整型运算对象,浮点值的输出形式不受影响
标准库在打印浮点数时,会自动选择一种可读性更好的格式(在用户未显示指定的情况下)
操纵符setprecision和其他接受参数的操纵符都定义在头文件iomanip中
注意指定精度的操纵符和IO对象的成员函数precision在使用上的区别
那些指定浮点数输出格式(记数法)的操纵符会改变流的默认精度的含义(你懂的)
在使用scientific或fixed的时候,我们可以进行按列打印(你懂的,但是效果好像并不好)
操纵符:boolalpha、noboolalpha、hex、oct、dec、showbase、noshowbase、uppercase、nouppercase、showpoint、noshowpoint、showpos、noshowpos、left、right、internal、fixed、scientific、hexfloat、defaultfloat、unitbuf、nounitbuf、skipws、noskipws、flush、ends、endl
默认情况下,输入运算符会忽略空白符(空格符、制表符、换行符、换纸符和回车符)
标准库还提供了一组低层操作,支持未格式化IO,这些操作允许我们将一个流当作一个无解释的字节序列来处理(低层函数容易出错,建议少用),用到时再研究。
*未格式化IO和C语言的I/O模型很像
各种流都支持对流中数据的随机访问,用到时再研究
到底什么是流: