zoukankan      html  css  js  c++  java
  • IO相关1(io类/流状态)

    IO类:

    iostream 定义了用于读写流的基本类型,fstream 定义了读写命名文件的类型,sstream 定义了读写内存 string 对象的类型。

    IO 库类型和头文件:

    头文件        类型

    iostream         istream,wistream 从流读取数据

                ostream,wostream 向流写入数据

                iostream,wiostream 读写流

    fstream           ifstream,wifstream 从文件读取数据

                ofstream,wofstream 向文件写入数据

                fstream,wfstream 读写文件

    sstream          istringstream,wistringstream 从 string 读取数据

                ostringstream,wostringstream 向 string 写入数据

                stringstream,wstringstream 读写 string

    其中前面加了 w 的是宽字符版本的

    为了支持使用宽字符的语言,标准库定义了一组类型和对象来操纵 wchar_t 类型的数据。宽字符版本的类型和函数的名字以一个 w 开始。例如:wcin,wcout,wcerr 是分别对应 cin,cout,cerr 的宽字符版对象。宽字符的类型和对象与其对应的普通 char 版本的类型定义在同一个头文件中。例如:头文件 fstream 定义了 ifstream 和 wifstream 类型。

    IO类型间的关系:

    标准库通过继承机制使我们能忽略不同类型的流之间的差异。利用模板,我们可以使用具有继承关系的类,而不必了解继承机制如何工作的细节。我们通常可以将一个派生类对象当作其基类对象类使用。

    类型 ifstream 和 istringstream 都继承自 istream。因此,我们可以像使用 istream 对象一样来使用 ifstream 和 istringstream 对象。也就是说我们是如何使用 cin 的,就可以同样地使用这些类型的对象。例如:可以对一个 ifstream 或者 istringstream 对象调用 getline,也可以使用 >> 从一个 ifstream 或 istringstream 对象中读取数据。类似的,类型 ofstream 和 ostringstream 都继承自 ostream。因此,我们可以如何使用 cout 的,就可以同样地使用这些类型的对象。

    IO对象无拷贝或赋值:

    1     ofstream out1, out2;
    2     out1 = out2;//错误,不能对流对象赋值
    3     ofstream frint(ofstream);//错误,不能初始化ofstream参数
    4     out2 = print(out2);//错误,不能拷贝流对象

    由于不能拷贝IO对象,因此我们也不能将形参或返回类型设置为流类型。进行IO操作的函数通常以引用方式传递和返回流。读写一个流会改变其状态,因此传递和返回的引用不能是 const 的。

    IO的条件状态:

    strm::iostate   strm是指一种IO类型,iostate是一种机器相关的类型,提供表达条件状态的完整功能。
    strm::badbit    标志流已崩溃,致命的输入/输出错误,无法挽回
    strm::failbit     标志IO操作失败了,非致命的输入/输出错误,可挽回 
    strm::eofbit     标志达到文件结尾
    strm::goodbit    流未出现错误状态,此值保证为0
    s.eof()       若流s的eofbit置位,则返回true
    s.fail()       若流s的failbit或badbit置位,则返回true
    s.bad()      若流s的badbit置位,则返回true
    s.good()    若流s处于有效状态,则返回true
    s.clear()    将流的所有条件复位,状态设置为有效,返回void
    s.clear(flags)  根据flags标志位,将s中对应条件状态复位,flags类型为strm::iostate。返回void
    s.setstate(flags)  根据flags标志位,将s中对应条件状态置位,flags类型为strm::iostate。返回void
    s.rdstate()    返回流的当前条件状态,返回类型为strm::iostate

    注意:

    badbit是系统级错误,如不可恢复的读写错误;一般badbit置位了流就无法继续使用。

    failbit是可恢复错误,例如希望读取数值,却读取了一个字符,这种错误可以修正,流还可以继续使用。

    如果达到文件结束位置,eofbit和failbit都会被置位。

    googbit表示流未发生错误,值为0。

    只要badbit、failbit、eofbit任意一个被置位,检查流的状态的条件会失败。

    管理条件状态:

    流对象的 rdstate 成员返回一个 iostate 值,对应流的当前状态。setstate 操作将给定条件位置位,表示发生了对应错误。cleat 成员是一个重载成员:他有一个不接受参数版本,而另一个版本接受一个 iostate 类型的参数。clear 不接受参数的版本清除所有错误标志位。执行 clear() 后调用 good 会返回 true:

    1      auto old_state = cin.rdstate();//记住cin当前的状态
    2      cin.clear();//使cin有效
    3      process_input(cin);//使用cin
    4      cin.setstate(old_state);//将cin置为原有状态

    带参数的 clear 版本接受一个 iostate 值,表示流的新状态。为了复位单一的条件状态,我们首先使用 rdstate 读出当前条件状态,然后用位操作将所需复位来生成新的状态。如:cin.clear(cin.rdstate()& ~cin.failbit & ~cin.badbit);//只复位failbit和badbit,但保持eofbit不变

    检查输入流的当前状态:

     1 #include <iostream>
     2 using namespace std;
     3 
     4 int main(void){
     5     int a;
     6     cin >> a;
     7     cout << cin.rdstate() << endl;
     8     if(cin.rdstate() == ios::goodbit) cout << "the input is true" << endl;
     9 
    10     std::wcout.imbue(locale(locale(), "", LC_CTYPE));
    11     if(cin.rdstate() == ios::failbit) wcout << L"输入数据类型错误,非致命错误,可清除输入缓冲区挽回!" << endl; 
    12 
    13     return 0;
    14 }

    通过 clear 使 cin 有效:

     1 #include <iostream>
     2 using namespace std;
     3 
     4 int main(void){
     5     int a;
     6     cin >> a;
     7     cout << cin.rdstate() << endl;
     8     cin.clear(ios::goodbit);//使cin有效
     9     cout << cin.rdstate() << endl;
    10     return 0;
    11 }

    通常当我们发现输入有错又需要改正的时候,使用 clear() 更改标记为正确后,同时也需要使用 get() 成员函数清除输入缓冲区,以达到重复输入的目的:

     1 #include <iostream>
     2 using namespace std;
     3 
     4 int main(void){
     5     int a;
     6     while(1){
     7         cin >> a;
     8         if(cin.fail()){
     9             cout << "error! please input agin!" << endl;
    10             cin.clear();
    11             cin.get();
    12         }else{
    13             cout << a;
    14             break;
    15         }
    16     }
    17     return 0;
    18 }

    管理输出缓冲:

    每个输出流都管理一个缓冲区,用来保存程序读写的数据:

    os << "please enter a value: ";

    文本串可能立即打印出来,也有可能被操作系统保存在缓冲区,随后再打印。

    会导致刷新缓冲区的原因:

    • 程序正常结束,作为 main 函数的 return 的一部分,缓冲刷新被执行。
    • 缓冲区满,需要刷新缓冲区,而后新的数据才能写入。
    • 使用操纵符:endl 来显示刷新缓冲区。
    • 每个输出操作后,可以用操作符unitbuf设置流的内部状态,来清空缓冲区。默认情况下,cerr 是设置 unitbuf 的,因此写到 cerr 中的数据都是立即刷新的。
    • 一个输出流被关联到另一个流,此时,当读写被关联的流时,关联到流的缓冲区会被刷新。默认cin 和 cerr 都关联到 cout,因此读 cin 或写 cerr 都会导致 cout 的缓冲区被刷新。

    endl  换行并刷新缓冲区;

    ends  插入一个空字符并刷新缓冲区;

    flush  仅刷新缓冲区;

    unibuf 操纵符:

    1     cout << unitbuf;//所有输出操作后都会立即刷新缓冲区
    2     //任何输出都立即刷新,无缓冲
    3     cout << nounitbuf;//回到正常的缓冲方式

    注意:如果程序异常终止,输出缓冲区是不会被刷新的。当一个程序崩溃后,它所输出的数据很可能停留在输出缓冲区中等待打印。

    关联输入和输出流:

    当一个输入流关联到一个输出流时,任何试图从输入流读取数据的操纵都会先刷新关联的输出流。标准库将 cout 和 cin 关联到一起,因此:

    cin >> val;

    导致 cout 的缓冲区被刷新。

    tie:

    tie 有两个重载版本:一个版本不带参数,返回指向输出流的指针。如果本对象关联到一个输出流,则返回的就是指向这个流的指针,如果对象未关联到流,则返回空指针。tie 的第二个版本接受一个指向 ostream 的指针,将自己关联到 ostream。即,x.tie(&o) 将流 x 关联到输出流 o。

    我们既可以将一个 istream 对象关联到另一个 ostream,也可以将一个 ostream 关联到另一个 ostream:

    1     cin.tie(&cerr);//直接将cin由和cout关联改成和cerr关联
    2     cin.tie(&cout);//将输入流cin关联到输出流cout
    3     ostream *old_tie = cin.tie(nullptr);//cin不再与其他流关联
    4     cin.tie(&cerr);//将cin关联到cerr,读取cin会刷新cerr而非cout
    5     cin.tie(old_tie);//重建cin和cout之间的关联

    注意:每个流同时最多关联到一个流,但多个流可以同时关联到一个 ostream。

  • 相关阅读:
    Biztalk 开发之 使用xml数据项构造输出文件路径【转】
    正则表达式限制文本框只能输入数字
    DropDownList、ListControl、RadioButtonList绑定
    下载文件代码
    C#几个经常用到的字符串截取
    在未被引用的程序集中定义。必须添加对程序集类型“System.Web.UI.WebControls.Panel”在未被引用的程序集中定义。必须添加对程序集“System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d
    Marquee滚动总结
    Jquery原理
    Menu控件绑定菜单代码
    .Net配置文件中数据库中连接字符串用法总结
  • 原文地址:https://www.cnblogs.com/geloutingyu/p/8253960.html
Copyright © 2011-2022 走看看