久治县wap网站建设公司,搜一下百度,建立公司企业网站,北京丰台网站建设公司我们的程序已经使用了很多IO库设施#xff1a;
istream(输入流)类型#xff0c;提供输入操作。ostream(输出流)类型#xff0c;提供输出操作。cin#xff0c;一个istream对象#xff0c;从标准输入读取数据。写入到标准错误。cout#xff0c;一个ostream对象#xff0c…我们的程序已经使用了很多IO库设施
istream(输入流)类型提供输入操作。ostream(输出流)类型提供输出操作。cin一个istream对象从标准输入读取数据。写入到标准错误。cout一个ostream对象向标准输出写入数据。cerr一个ostream对象通常用于输出程序错误消息运算符用来从一个istream对象读取输入数据。运算符用来向一个ostream对象写入输出数据。getline函数(参见3.3.2节第78页)从一个给定的istream读取一行数据存入一个给定的string对象中。 IO类
到目前为止我们已经使用过的IO类型和对象都是操纵char数据的。
默认情况下这些对象都是关联到用户的控制台窗口的。
当然我们不能限制实际应用程序仅从控制台窗口进行IO操作应用程序常常需要读写命名文件。而且使用IO操作处理string中的字符会很方便。此外应用程序还可能读写需要宽字符支持的语言。
为了支持这些不同种类的IO处理操作在istream和ostream之外标准库还定义了其他一些IO类型我们之前都已经使用过了。
下表列出了这些类型分别定义在三个独立的头文件中
iostream定义了用于读写流的基本类型fstream定义了读写命名文件的类型sstream定义了读写内存string对象的类型。
IO库类型和头文件 头文件类型iostreamistream wistream从流读取数据 ostream, wostream向流写入数据 iostream, wiostream读写流fstreamifstreamwifstream从文件读取数据 ofstream, wofstream向文件写入数据 fstreamwfstream读写文件sstreamistringstreamwistringstream从string读取数据 ostringstream, wostringstream向string写入数据 stringstream, wstringstream读写string 为了支持使用宽字符的语言标准库定义了一组类型和对象来操纵 wchar_t类型的数据。宽字符版本的类型和函数的名字以一个w开始。
例如wcin、 woout 和wcerr是分别对应cin、cout 和cerr的宽字符版对象。宽字符版本的类型和对象与其对应的普通char版本的类型定义在同一个头文件中。
例如头文件fstream定义了ifstream和wifstream类型。
IO类型间的关系
概念上设备类型和字符大小都不会影响我们要执行的操作。
例如我们可以用读取数据而不用管是从一个控制台窗口一个磁盘文件还是一个string读取。类似的我们也不用管读取的字符能存入一个char对象内还是需要一个wchar_t对象来存储。
标准库使我们能忽略这些不同类型的流之间的差异这是通过继承机制实现的。
利用模板我们可以使用具有继承关系的类而不必了解继承机制如何工作的细节。
类型ifstream和istringstream都继承自istream。
因此我们可以像使用istream对象一样来使用ifstream和istringstream对象。
也就是说我们是如何使用cin的就可以同样地使用这些类型的对象。
例如可以对一个 ifstream或istringstream对象调用 getline也可以使用从一个ifstream或istringstream对象中读取数据。
类似的类型ofstream和ostringstream都继承自ostream。因此我们是如何使用cout的就可以同样地使用这些类型的对象。 本节剩下部分所介绍的标准库流特性都可以无差别地应用于普通流、文件流和string流以及char或宽字符流版本。 IO对象无拷贝或赋值
我们不能拷贝或对IO对象赋值
ofstream outl, out2;
outl out2; // 错误不能对流对象赋值
ofstream print (ofstream) ;// 错误不能初始化ofstream参数
out2 print (out2); //错误不能拷贝流对象
由于不能拷贝IO对象因此我们也不能将形参或返回类型设置为流类型。
进行IO操作的函数通常以引用方式传递和返回流。
读写一个IO对象会改变其状态因此传递和返回的引用不能是const的。
条件状态
IO 操作一个与生俱来的问题是可能发生错误。
一些错误是可恢复的而其他错误则发生在系统深处已经超出了应用程序可以修正的范围。
表中列出了IO类所定义的一些函数和标志可以帮助我们访问和操纵流的条件状态。
IO库条件状态 strm::iostatestrm 是一种IO类型。iostate是一种机器相关的类型提供了表达条件状态的完整功能strm::badbitstrm::badbit用来指出流已崩溃strm::failbitstrm::failbit 用来指出一个IO操作失败了stm::eofbitstrm::eofbit用来指出流到达了文件结束stm::goodbitstrm::goodbit用来指出流未处于错误状态。此值保证为零s.eof()若流s的eofbit置位则返回trues.fail()若流s的failbit或badbit置位则返回trues.bad()若流s的badbit置位则返回trues.good()若流s处于有效状态则返回trues.clear()将流s中所有条件状态位复位将流的状态设置为有效。返回voids.clear(flags)根据给定的flags标志位将流s中对应条件状态位复位。flaqs的类型为strm::iostate。返回voids.setstate(flags)根据给定的flags标志位将流s中对应条件状态位置位。flags的类型为strm::iostate。返回voids.rdstate()返回流s的当前条件状态返回值类型为strm::iostate 下面是一个IO错误的例子
int ival;
cin ival;
如果我们在标准输入上键入Boo读操作就会失败。
代码中的输入运算符期待读取一个int但却得到了一个字符B。这样cin会进入错误状态。类似的如果我们输入一个文件结束标识cin也会进入错误状态。
一个流一旦发生错误其上后续的IO操作都会失败。只有当一个流处于无错状态时我们才可以从它读取数据向它写入数据。
由于流可能处于错误状态因此代码通常应该在使用一个流之前检查它是否处于良好状态。
确定一个流对象的状态的最简单的方法是将它当作一个条件来使用
while (cin word)
//ok读操作成功… while 循环检查表达式返回的流的状态。如果输入操作成功流保持有效状态则条件为真。
查询流的状态
将流作为条件使用只能告诉我们流是否有效而无法告诉我们具体发生了什么。
有时我们也需要知道流为什么失败。
例如在键入文件结束标识后我们的应对措施可能与遇到一个IO设备错误的处理方式是不同的。
IO库定义了一个与机器无关的iostate类型它提供了表达流状态的完整功能。
这个类型应作为一个位集合来使用。
IO库定义了4个iostate类型的constexpr值表示特定的位模式。
这些值用来表示特定类型的IO条件可以与位运算符一起使用来一次性检测或设置多个标志位。
badbit表示系统级错误如不可恢复的读写错误。通常情况下一旦badbit被置位流就无法再使用了。
在发生可恢复错误后failbit 被置位如期望读取数值却读出一个字符等错误。这种问题通常是可以修正的流还可以继续使用。
如果到达文件结束位置eofbit和failbit都会被置位。goodbit的值为0表示流未发生错误。
如果badbit、failbit和eofbit任一个被置位则检测流状态的条件会失败。
标准库还定义了一组函数来查询这些标志位的状态。
操作good在所有错误位均未置位的情况下返回true而bad、fail和eof则在对应错误位被置位时返回true。
此外在badbit被置位时fail也会返回true。这意味着使用good或fail是确定流的总体状态的正确方法。实际上我们将流当作条件使用的代码就等价于!fail()。而eof和bad操作只能表示特定的错误。
管理条件状态
流对象的rdstate成员返回一个iostate值对应流的当前状态。
setstate 操作将给定条件位置位表示发生了对应错误。
clear成员是一个重载的成员它有一个不接受参数的版本而另一个版本接受一个iostate类型的参数。
clear不接受参数的版本清除(复位)所有错误标志位。执行clear()后调用good会返回true。
我们可以这样使用这些成员
//记住cin的当前状态
auto old state cin.rdstate();// 记住 cin的当前状态
cin.clear(); // 使cin有效
process_input (cin); //使用cin
cin.setstate(old state); // 将cin置为原有状态
带参数的clear版本接受一个iostate值表示流的新状态。
为了复位单一的条件状态位我们首先用rdstate读出当前条件状态然后用位操作将所需位复位来生成新的状态。
例如下面的代码将failbit和badbit复位但保持eofbit不变
//复位failbit和badbit保持其他标志位不变
cin.clear(cin.rdstate() ~cin.failbit ~cin.badbit); 管理输出缓冲
每个输出流都管理一个缓冲区用来保存程序读写的数据。
例如如果执行下面的代码
os please enter a value:;
文本串可能立即打印出来但也有可能被操作系统保存在缓冲区中随后再打印。
有了缓冲机制操作系统就可以将程序的多个输出操作组合成单一的系统级写操作。
由于设备的写操作可能很耗时允许操作系统将多个输出操作组合为单一的设备写操作可以带来很大的性能提升。 导致缓冲刷新(即数据真正写到输出设备或文件)的原因有很多 程序正常结束作为main函数的return操作的一部分缓冲刷新被执行。缓冲区满时需要刷新缓冲而后续的数据才能继续写入缓冲区。我们可以使用操纵符如endl来显式刷新缓冲区。在每个输出操作之后我们可以用操纵符unitbuf设置流的内部状态来清空缓冲区。默认情况下对cerr是设置unitbuf的因此写到cerr的内容都是立即刷新的一个输出流可能被关联到另一个流。在这种情况下当读写被关联的流时关联的流的缓冲区会被刷新。例如默认情况下cin和cerr都被关联到cout读cin或写cexr都会导致cout的缓冲区被刷新。 刷新输出缓冲区
我们已经使用过操纵符endl它完成换行并刷新缓冲区的工作。
IO库中还有两个类似的操纵符flush和ends。
flush刷新缓冲区但不输出任何额外的字符ends向缓冲区插入一个空字符然后刷新缓冲区
cout hi! endl; //输出hi和一个换行然后刷新缓冲区
cout hi! flush;//输出hi然后刷新缓冲区不附加任何额外字符cout hi! ends;// 输出hi和一个空字符然后刷新缓冲区
unitbuf 操纵符
如果想在每次输出操作后都刷新缓冲区我们可以使用unitbuf操纵符。
它告诉流在接下来的每次写操作之后都进行一次flush操作。
而nounitbuf操纵符则重置流使其恢复使用正常的系统管理的缓冲区刷新机制
cout unitbuf; // 所有输出操作后都会立即刷新缓冲区
// 任何输出都立即刷新无缓冲
cout nounitbuf; // 回到正常的缓冲方式 警告如果程序崩溃输出缓冲区不会被刷新 如果程序异常终止输出缓冲区是不会被刷新的。当一个程序崩溃后它所输出的数据很可能停留在输出缓冲区中等待打印。 当调试一个已经崩溃的程序时需要确认那些你认为已经输出的数据确实已经刷新了。否则可能将大量时间浪费在追踪代码为什么没有执行上而实际上代码已经执行了只是程序崩溃后缓冲区没有被刷新输出数据被挂起没有打印而已。 关联输入和输出流
当一个输入流被关联到一个输出流时任何试图从输入流读取数据的操作都会先刷新关联的输出流。
标准库将cout和cin关联在一起
因此下面语句
cin ival;
导致cout的缓冲区被刷新。 交互式系统通常应该关联输入流和输出流。这意味着所有输出包括用户提示信息都会在读操作之前被打印出来。 tie有两个重载的版本一个版本不带参数返回指向输出流的指针。
如果本对象当前未关联到一个输出流则返回的就是指向这个流的指针如果对象未关联到流则返回空指针。
tie的第二个版本接受一个指向ostream的指针将自己关联到此ostream。即x.tie(o)将流x关联到输出流o。
我们既可以将一个istream对象关联到另一个ostream也可以将一个ostream关联到另一ostream:
cin.tie(cout); // 仅仅是用来展示标准库将cin和cout关联在一起// old tie指向当前关联到cin的流(如果有的话)
ostream *old tie cin.tie(nullptr); // cin不再与其他流关联//将cin与cerr关联这不是一个好主意因为cin应该关联到cout
cin.tie(cerr); // 读取cin会刷新cerr而不是coutcin.tie(old tie); //重建cin和cout间的正常关联 在这段代码中为了将一个给定的流关联到一个新的输出流我们将新流的指针传递给了tie。
为了彻底解开流的关联我们传递了一个空指针。每个流同时最多关联到一个流但多个流可以同时关联到同一个ostream。