一、IO类:
IO库类型和头文件:
iostream 定义了用于读写流的基本类型;
fstream 定义了读写命名文件的类型;
sstream 定义了读写内存string对象的类型。
为了支持使用宽字符的语言,标准库定义类型和函数的名字以一个w开始。
头文件 | 类型 |
iostream | istream,wistream 从流读取数据 |
ostream,wostream 向流中写入数据 | |
iostream,wiostream 读写流 | |
fstream | ifstream,wifstream 从文件读取数据 |
ofstream.wofstream 向文件写入数据 | |
fstream,wfstream 读写文件 | |
sstream | istringstream,wistringstream 从string读取数据 |
ostringstream.wostringstream 向string写入数据 | |
stringstream,wstringstream 读写string |
IO类型间的关系:
标准库通过继承机制,利用模板,使设备的类型和字符大小都不会影响我们执行IO操作。
ifstream和istringstream都继承自istream。
1.1、IO对象无拷贝或赋值
ostream out1, out2; out1 = out2; //错误:不能对流对象赋值 ofstream print(ofstream); //错误:不能初始化ofstream参数 out2 = print(out) //错误:不能拷贝流对象
由于不能拷贝IO对象,所以进行IO操作的函数通常以引用方式传递和返回流。读写一个IO对象会改变其状态,因此传递和返回的引用不能使const的。
1.2、条件状态
strm::iostate | strm是一种IO类型。iostate是一种机器相关的类型,提供了表达条件状态的完整功能; |
strm::badbit | 用来指出流已经崩溃; |
strm::failbit | 用来指出一个IO操作失败了; |
strm::eofbit | 用来指出流到达了文件结束; |
strm::goodbit | 用来指出流没有处于错误状态,此值保证为零; |
s.eof() | 若流s的eifbit位置,则返回true; |
s.fail() |
若流s的failbit或badbit位置,则返回true; |
s.good() |
若流处于有效状态,则返回true; |
s.bad() | 若流处于badbit位置,则返回true; |
s.clear() | 将流s中所有条件状态位复位,将流的状态位设置为有效,返回void; |
s.clear(flags) | 根据给定的flags标志位,将流s中对用条件状态位复位; |
s.setstate(flags) | 根据给定的flag标志位,将流s中对应条件状态位置位; |
s.rdstate() | 返回流s的当前条件状态。 |
代码通常应该在使用一个流之前检查它是否处于良好状态。确定一个流对象的状态的最简单的方法是将它当作一个条件来使用:
while(cin >> word) //ok:读操作成功
查询流的状态:
IO库定义了一个与机器无关的iostate类型,它提供了表达流状态的完整功能。IO库定义了4个iostate类型的constexpr值。
badbit表示系统级错误,如不可恢复的读写错误,流无法再使用;
failbit1表示可恢复的读写错误,流还是可以用的;
如果到达文件结束位置,eofbit和failbit都会被置位;
goodbit的值位0,表示流未发生错误。
如果badbit和failbit、eofbit任一被置位,则检测流状态的条件会失败。
实际上,我们将流当作条件使用的代码就等价于!fail()。
管理条件状态:
rdstate返回一个iostate的值,对应流的当前状态;
setstate操作将给定条件位置为,表示发生了对应的错误。
1.3、管理输出缓冲
每个输出流都管理一个缓冲区,用来保存程序读写的数据。
文本串有可能立即打印出来,也有可能被操作系统保存在缓冲区中,随后打印出来。
有了缓冲机制,操作系统就可以将程序的多个输出操作组合程单一的系统级写操作。
其中,导致缓冲刷新的原因有:
- 程序正常结束;
- 缓冲区满;
- 使用操纵符endl;
- 在每个输出操作之后,我们可以用操纵符unitbuf设置流的内部状态,来清空缓冲区;
- 一个输出流可能被关联到另一个输出流。
刷新输出缓冲区:
操纵符endl,完成换行并刷新缓冲区的工作;
操纵符flush,刷新缓冲区,但不输出任何额外的字符;
操纵符ends,向缓冲区插入一个空字符,然后刷新缓冲区。
cout << "hi!" << endl; cout << “hi!” << flush; cout << "hi!" << ends;
unitbuf操作符:
如果想在每次操作后都刷新缓冲区,则我们可以使用unitbuf操纵符。它告诉缓冲区,在每一次操作之后都进行一次flush操作。而nounitbuf操纵符,则重置流,恢复使用正常的系统管理缓冲区刷新。
cout << unitbuf; //所有输出操作后都会立即刷新缓冲区 ..................//任何输出都立即刷新,无缓冲 cout << nounitbuf;//恢复正常的缓冲方式
关联输入和输出流
当一个输入流被关联到一个输出流时,任何试图从输入流读取数据的操作都会先刷新关联的输出流,
tie有两个重载版本:
- 不带参数,返回指向输出流的指针。如果本对象关联到一个输出流,则返回的就是指向这个流的指针。如果没有关联,则返回空指针;
- 带参数,将自己关联到输出流。即,x.tie(&o)将流x关联到输出流o。
2、文件输入输出
fstream fstrm | 创建一个未绑定的文件流。fstrm时头文件fstream定义的一个类型。 |
fstream fstrm(s) | 创建一个fstream,并打开名为s的文件。s可以是string类型,或者是一个指向C风格字符串的指针。 |
fstream fstrm(s,mode) |
与前一个构造函数类似,但按指定的mode打开文件。 |
fstrm.open(s) | 打开名为s的文件,并将文件与fstrm绑定。s可以是一个string或一个指向C风格字符串的指针。 |
fstrm.close() | 关闭与fstrm绑定的文件。返回void |
fstrm.is_open() | 返回一个bool值,指出与fstrm关联的文件是否成功打开或者尚未关闭。 |
2.1、使用文件流对象
用fstream替代iostream&
成员函数open和close
2.2、文件模式
in | 以读方式打开 |
out | 以写方式打开 |
app | 每次写操作钱均定为到文件末尾 |
ate | 打开文件后立即定位到文件末尾 |
trunc | 截断文件 |
binary | 以二进制方式进行IO |
以out模式打开文件会丢弃已有数据:
保留被ofstream打开的文件中已有数据的唯一方法是显式指定app或in模式。
每次调用open时都会确定文件模式:
对于一个给定流,每当打开文件时,都可以改变其文件模式。
3、string流
sstream strm |
strm是一个未绑定的stringstream对象。sstream是头文件sstream中定义的一个类型。 |
sstream strm(s) | strm是一个sstream对象,保存string s的一个拷贝。 |
strm.str() | 返回strm所保存的string的拷贝。 |
strm.str(s) | 将string s 拷贝到strm中,返回void。 |
3.1 使用istringstream
3.2使用ostringstream