IO类
在istream和ostream之外,标准库还定义了一些其他的IO类型。
IO库类型和头文件
头文件 | 类型 |
---|---|
iostream | istream.wistream 从流读取数据 ostream.wostream向流写入数据 iostream.wiostream读写流 |
fstream | ifstream.wifstream从文件读取数据 ofstream.wofstream向文件写入数据 fstream.wfstream读写文件 |
sstream | istringstream.wistringstream从string读取数据 ostringstream.wostringstream向string写入数据 stringstream.wstringsteam读写string |
为了支持宽字符语言,标准库定义了一组类型和对象来操纵wchar_t类型的数据。如wcin,wcout和werr分别对应cin,cout和cerr
IO对象无拷贝或赋值
因此,我们也不能将形参或返回类型设置为流类型,进行IO操作的函数通常以引用方式传递和返回流。且不能是const。
条件状态
IO库,访问和操作流的条件状态
strm::iostate | strm是一种IO类型,iostate是一种机器相关的类型,提供了表达条件状态的完整功能 |
strm::badbit | strm::badbit用来指出流已崩溃 |
strm::failbit | strm::failbit用来指出一个IO操作失败了 |
strm::eofbit | strm::eofbit用来指出流到达了文件结束 |
strm::goodbit | strm::goodbit用来指出流末处于错误状态,此值保证为0 |
s.eof() | 若流s的eofbit置位,则返回true |
s.fail() | 若流s的fallbit或badbit置位,则返回true |
s.bad() | 若流s的badbit置位,则返回true |
s.good() | 若流s处于有效状态,则返回true |
s.clear() | 将流s中的所有条件状态复位,将流的状态设置为有效,返回void |
s.clear(flags) | 根据给定flags标志位,将流s中的对应条件状态位复位,flags类型为strm::iostate,返回void |
s.setstate(flags) | 根据给定flags标志位,将流s中对应条件状态位置位,flags的类型为strm::iostate。返回void |
s.rdstate() | 返回流s的当前条件状态,返回值类型为strm::iostate |
管理输出缓冲
每个输出流都管理一个缓冲区,用来保存程序读写的数据
有了缓冲机制,操作系统就可以将程序的多个输出操作组合成单一的系统级写操作。由于设备的写操作可能很耗时,允许操作系统将多个输出操作组合为单一的设备写操作可以带来很大的性能提升。
导致缓冲刷新(即数据真正写到输出设备或文件)的原因有很多:
- 程序正常结束,作为main函数的return操作的一部分,缓冲刷新被执行。
- 缓冲区满时,需要刷新缓冲,而后新的数据才能继续写入缓冲区。
- 我们可以使用操作符如endl来显式刷新缓冲区。
- 在每个输出操作之后,我们可以用操作符unitbuf设置流的内部状态,来清空缓冲区,默认情况下,对cerr是设置unitbuf的,因此写到cerr的内容都是立即刷新的。
- 一个输出流可能被关联到另一个流。在这种情况下,当读写被关联的流时,关联到的流的缓冲区会被刷新。
刷新输出缓冲区
cout<< "hi!" << endl; //输出hi和一个换行,然后刷新缓冲区
cout<< "hi!" << flush; //输出hi,然后刷新缓冲区,不附加任何额外字符串
cout<< "hi" << ends; //输出hi和一个空字符串,然后刷新缓冲区。
unitbuf操作符
如果想在没次输出操作后都刷新缓冲区,我们可以使用unitbuf操作符。他告诉流接下来的每次操作之后都进行一次flush操作。
cout<<unitbuf; //所有输出操作后都会立即刷新缓冲区
cout<<nounitbuf; //回到正常的缓冲方式
关联输入和输出流
当一个输入流被关联到一个输出流时,任何试图从输入流读取数据的操作都会先刷新关联的输出流。标准库将cout和cin关联在一起,因此下面语句:
cin >> ival;
导致cout的缓冲区被刷新。
交互式系统通常应该关联输入流和输出流,这意味着所有输出,包括用户提示信息,都会在读操作之前被打印出来。
文件输入输出
文件的输入输出提供的操作符和之前cin,cout的操作一行。特别是可以用IO运算符<<和>>来读写文件。可以用getline从一个ifsteam读取数据。
除了这些以外,fstream中还定义了一些新的成员来管理ifstream对象和ofstream对象调用这些操作:
fstream fstrm; | 创建一个未绑定的文件流。fstream是头文件fstream中定义的一个类型 |
fstream fstrm(s); | 创建一个fstream,并打开名为s的文件。s可以是string类型,或者是一个指向c风格字符串的指针。 |
fstream fstrm(s, mode); | 与前一个构造函数类似,但按指定mode打开文件 |
fstrm.open(s); | 打开名为s的文件,并将文件与fstrm绑定。 返回void |
fstrm.close(); | 关闭与fstrm绑定的文件,返回void |
fstrm.is_open(); | 返回一个bool值,指出与fstrm关联的文件是否成功打开且尚未关闭 |
使用文件流对象
如果一个函数接受一个ostream&参数,我们在调用这个函数的时候,可以传递给他一个ofstream对象,对istream&和ifstream也是类似的。
文件模式
每个文件都有一个关联的文件模式,用来指出如何使用文件。
in | 以读方式打开 |
out | 以写方式打开 |
app | 每次写操作前均定位到文件末尾 |
ate | 打开文件后立即定位到文件末尾 |
trunc | 截断文件 |
binary | 以二进制方式进行IO |
以out模式打开文件会丢失已有数据
每次调用open时都会确定文件模式
string流
sstream strm; | strm是一个未绑定的stringstream对象。sstream是头文件sstream中定义的一个类型 |
sstream strm(s) | strm是一个sstream对象,保存strings的一个拷贝。此构造函数是explicit的 |
strm.str() | 返回strm所保存的string的拷贝 |
strm.str(s) | 将string s拷贝到strm中,返回void |
使用istringstream
当我们使用某些工作是对整行文本进行处理,而其他工作是处理行内的单个单词,通常可以使用istringstream。