现在的位置: 首页 > 综合 > 正文

C++ io流及其标志位

2014年07月02日 ⁄ 综合 ⁄ 共 6880字 ⁄ 字号 评论关闭

O标准库类型和头文件
   头文件
   iostream                    istream从流中读取
                               ostream写到流中去
                               iostream对流进行读取;从istream和ostream派生而来
   fstream                     ifstream从文件中读取
                               ofstream写到文件中去,由ostream派生而来
                               fstream读写文件,由iostream派生而来
   sstream                     istringstream从string对象读取:由istream派生而来
                               ostreamstream写到string对象中去;由ostream派生而来
                               stringstream对string对象进行读写;由iostream派生而来
   IO类型在三个独立的头文件中定义:iostream定义读写控制窗口的类型,fstream定义读写已命名文件的类型,而sstream所定义的类型则用于读写存储在内存中的string对象。
   对istream&进行操作的函数,也可使用ifstream或者istringstream对象来调用。类似的,形参为ostream&类型的函数也可用ofstream或者ostringstream对象调用。因为IO通过继承关联,所以可以只编写一个函数,而将他应用到三种类型的流上:控制台,磁盘文件或者字符串流。
1. 国际字符的支持
   除了支持读写是由char类型组成的流外,标准库还定义了一组相关的类型,支持wchar_t类型。每个类都加上w,以此与char类型的版本区分开来。于是,wostream,wistream和wiostream可以从控制窗口读写wchat_t类型的数据。相应的文本输入输出类是wifstream,wofstream和wfstream。同样,wchar_t的读入类型是wcin,标准输出是wcout;而标准错误是wcerr。
2. IO对象不可赋值或复制
   由于流对象不能复制,因此不能存储在vector或其他容器中。另外,形参或返回类型不能为流类型。如果需要传递或返回IO对象,则必须传递返回指向该对象的指针或引用。
   一般情况下,如果需要对传递IO的对象进行读写,可用非const引用方式传递这个流对象。
二. 条件状态
   IO标准库的条件状态
   strm::iostate           机器相关的类型名,由各个iostream类定义,用于条件状态
   strm::badbit           strm::iostate类型的值,用于指出被破坏的流
   strm::failbit           strm::iostate类型的值,用于指出失败的IO操作
   strm::eofbit           strm::iostate类型的值,用于指出流已经达到文件结束符。
   s.eof()               如果设置了流s的eofbit值,则该函数返回true。
   s.fail()               如果设置了流s的failbit值,则返回true。
   s.bad()               如果设置了流s的badbit值,则返回true。
   s.good()              如果流s处于有效状态,则该函数返回ture。
   s.clear()              将s中的所有状态值都重设为有效状态
   s.clear(flag)           将流s中的某个指定条件状态设为有效。Flag的类型是
   strm::iostate
   s.setstate(flag)         给流s添加指定条件,flag的类型是strm::iostate
   s.rdstate()             返回流s的当前条件,返回值类型为strm::iostate
   流必须处于无错误状态,才能用于输入和输出。检查流是否可用的最简单方法是检查其真值:
   if(cin)
    //ok, 可以使用cin,它为合法值
   while(cin>>word)

    //ok.成功读取操作

最后来看看如何利用rdstate()函数和输入状态标记位常量来判断输入流的状态:
  #include <iostream>
  using namespace std;
  int main()
  {
  int a;
  cin>>a;
  cout<<cin.rdstate()<<endl;
  if(cin.rdstate() == ios::goodbit)
  {
  cout<<"输入数据的类型正确,无错误!"<<endl;
  }
  if(cin.rdstate() == ios::failbit)
  {
  cout<<"输入数据类型错误,非致命错误,可清除输入缓冲区挽回!"<<endl;
  }
  system("pause");
  return 0;
  }
  利用前面所讲的rdstate() 函数返回值原理和输入状态标记位常量表,不难理解:
  rdstate() 函数返回当前流对象的failbit、eofbit、badbit3个标记位状态的十进制值
  输入状态格式常量也是failbit、eofbit、badbit3个标记位状态的十进制值
  比如cin流状态读取错误,即failbit标记位为1,eofbit标记位为0,badbit标记位为0,则:
  cin.rdstate()的返回值为4,而格式常量ios::failbit的十进制也是4
  因此,if(cin.rdstate() == ios::failbit) 判断为Ture
  因此程序当中的两个if语句能有效识别出流状态
  再来看看有些许不同的程序:
  #include <iostream>
  using namespace std;
  int main()
  {
  cin.setstate(ios::failbit);
  cin.setstate(ios::eofbit);
  cout<<cin.rdstate()<<endl;
  if(cin.rdstate() == ios::goodbit)
  {
  cout<<"输入数据的类型正确,无错误!"<<endl;
  }
  if(cin.rdstate() == ios::failbit)
  {
  cout<<"输入数据类型错误,非致命错误,可清除输入缓冲区挽回!"<<endl;
  }
  system("pause");
  return 0;
  }
  输出结果为:
  6
  请按任意键继续...
  原因为何?
  cin流状态被设置成failbit标记位置为1,eofbit标记位置为1,badbit标记位为0
  那么cin.rdstate()的返回值二进制为110,十进制为6,即输出6。
  参照输入状态标记位常量表:
  ios::goodbit的二进制为000,十进制为0,因此if(cin.rdstate() == ios::goodbit)判断为False
  ios::failbit的二进制为100,十进制为4,因此if(cin.rdstate() == ios::failbit)判断为False
  然后system("pause"); 语句使得输出 请按任意键继续...
  很有意思吧,cin对象明明failbit标记位为1,但表达式cin.rdstate() == ios::failbit却是False,这就是原因。
  rdstate()函数与输入状态标记位常量的对比是严格按照数值对比的。

1. 条件状态
   所有流对象都包括一个条件状态成员,该成员分别有setstate和clear操作管理。这个状态成员为iostate类型。这是由各个iostream类分别定义的机器相关类型。该状态成员以二进制的形式使用。
   badbit标志着系统级的故障,如无法恢复的读写错误。如果出现了这样的错误,则该流通常就不能在继续使用了。如果出现的是可恢复错误,此时则设置failbit标志,这种导致了failbit的问题是可以修正的。Eofbit实在遇到文件结束符设置的,此时同时还设置了failbit。
   流的状态由bad,fail,eof和good操作表示。如果bad,fail或者eof任意一个为ture,则检查流本身将显示该流处于错误状态。类似的,如果这三个条件没有一个为true。则good操作将返回true。
2. 条件状态的访问
   rdstate成员函数返回一个iostate类型的值,该值对应于流当前的整个条件状态。
   istream::iostate old_state=cin.rdstate();
   cin.clear();
   process_input():
   cin.clear(old_state):
3. 多种状态的处理
   常常会出现设置或清楚多个二进制的情况。此时,可以通过多次调用setstate或者clear函数实现。另外一种方法则是安位或操作符来实现。
   is.setstate(ifstream::badbit | ifstream::failbit);
三. 输出缓冲区的管理
   每个IO对象管理一个缓冲区,用于存储程序读写的数据。
   os<<" please enter a value: ";
   系统将字符串字面值存储在与流os相关联的缓冲区中,下面几种情况将导致缓冲区的内容被刷新,即写入到真实的输出设备或者文件:
a. 程序正常结束。作为main函数返回工作的一部分,将清空所有输出缓冲区。
b. 在一些不确定到时候,缓冲区可能满了,缓冲区在写入下一个值之前刷新。
c. 用操作符显式的刷新缓冲区,例如行换行符endl。
d. 在每次输出操作执行完后,用unitbuf操作符设置流的内部状态,从而情况缓冲区。
e. 可将输入流和输出流关联起来,在这种情况下,在读输入流时将刷新其关联的输出缓冲区。
1. 输出缓冲区的刷新
   除了endl操作符,C++还提供了另外的两个类似的操纵符。第一个是经常使用的flush,用于刷新流,但仍然不再输出中添加任何字符。第二个是比较少用的ends,这个操作在缓冲区中插入空字符null,然后刷新它。
2. unitbuf操纵符
   如果需要刷新所有输出,最好使用unitbuf操作符。这个操作符在每次执行完写操作后都刷新流:
   cout<< unitbuf <<"first"<<"second"<<nounitbuf;
   nounitbuf操纵符将流恢复为正常的,由系统管理的缓冲区刷新方式。
   如果程序崩溃了,则不会刷新缓冲区。如果程序不正常结束,输出缓冲区将不会被刷新。
3. 将输入和输出绑在一起
   当输入流和输出流绑在一起时,任何读输入流的尝试都将首先刷新其输出流相关联的缓冲区。标准库将count和cin绑在一起。语句:cin>>ival;导致cout关联的缓冲区被刷新。交互式系统通常应确保它们的输入和输出流是绑在一起的。这样做意味着可以保证任何输出,包括给用户的提示,都在试图读之前输出。
   Tie函数可以用istream或ostream对象调用,使用一个指向ostream对象的指针形参。调用tie函数时,将实参流绑在调用该函数的对象上,如果一个流调用tie函数将其本身绑定在传递给tie的ostream实参对象时,则该流上的任何IO操作都会被刷新实参所关联的缓冲区。
四. 文件的输入与输出
   fstream头文件中定义了三种支持文件IO的类型:
a. ifstream,由istream派生而来。
b. ofstream,由ostream派生而来
c. fstream,由iostream派生而来
   fstream类型除了继承下来的行为外,还定义了两个自己的新操作,open和close,以及形参为要打开的文件名的构造函数。fstream,ifstream,ofstreram对象可以调用这些操作,其他的IO类型不能调用。
1. 文件流对象的使用
   有两种方式:
a.直接用带参数的够造函数打开一个文件名为string类型的ifile,
   ifstream infile(ifile.c_str());
b.使用默认构造函数初始化一个文件流对象,然后调用open函数。
   ifstream infile;
   infile.open("in");
   检查文件是否打开成功,这是一个好习惯:
   if(!infile)
   {
     cerr<<"error: unable to open input file: "<<ifile<<endl;
     return -1;
   }
   将文件流与新文件重新绑定
   fstream对象一旦打开,就保持与指定文件相关联。如果要把fstream对象与另一个不同的文件关联,则必须先关闭现在的文件,然后打开另一个文件。
   ifstream infile("in");
   infile.close();
   infile.open("next");
   清除文件流的状态
   关闭流不能改变流对象的内部状态。如果最后的读写操作失败了,对象的状态保持为错误模式,直到指向clear操作重新恢复流的状态为止。调用clear后,就像重新创建了个对象一样。如果程序员要重用文件流读写多个文件,必须在读另一个文件之前调用clear清除该流的状态。
2. 文件模式
   in       打开文件做读操作
   out      打开文件做写操作
   app     在每次写之前找到文件尾
   ate      打开文件后立即定位在文件尾
   trunc    打开文件时清空已存在的文件流
   binary   以二进制模式进行IO操作
   out,trunk,和app模式只能用于指定与offstream或fstream对象关联的文件;in模式只能用于指定与ifstream或fstream对象相关联的文件。所有的文件都可以用ate或binary模式打开。Ate模式只有在打开时有效:文件打开后将定位在文件尾。以binary模式打开的流则将文件以字节的形式处理,不解释流中的字符。
   默认时,与ifstream流对象关联的文件将以in模式打开,该模式运行文件做读的操作,与ofstream关联的文件则以out模式打开,使文件可写。从效果来看,为ofstream对象指定了out模式等效于同时指定了out和trunc模式。对于ofstream打开的文件,要保存文件中已存在的数据,唯一方法是显式的指定app模式打开。
a. 对同一文件做输入和输出运算
   fstream对象既可读也可写它所关联的文件。Fstream如何使用它的文件取决于打开文件时指定的模式。默认情况下,fstream对象是以in和out模式同时打开。当文件同时以in和out打开时不清空。如果打开fstream所关联的文件时,只用out模式,而不用in模式,则文件清空已存在的数据,如果打开指定了trunc模式,无论是否同时指定了in模式,文件同样会被清空。
b. 模式是文件的属性而不是流属性
   只要调用open函数,就要设置文件模式,其模式的设置可以是显式的,也可以是隐式的。如果没有指定文件模式,将使用默认值。
c. 打开模式的有效组合
   out ;  out | app ;  out | trunc ;  in ;  in | out ;   in | out | trunk;
五. 字符串流
   istringstream,由istream派生而来,提供读string的功能
   ostringstream 由ostream派生而来,提供写string的功能
   stringstream  由iostream派生而来,提供读写string的功能
   stringstream除了继承基类的操作外,还各自定义一个又string形参的构造函数,这个构造函数将string类型实参复制给stringstream对象。
   stringstream特定的操作
   stringsteam strm;   创建自由的stringstream对象
   stringstream strm(s); 创建存储s的副本的stringstream对象,其中s是string类型的对象。
   strm.str();        返回strm中存储的string类型对象
   strm.str(s);       返回string类型的s复制给strm,返回void。
1. stringstream对象的使用
   将一个stringstream对象与所读取的行绑定起来,这样只需使用普通的string输入操作符即可读出每行中的单词。
   String line, word;
   While ( getline(cin, line))
   {
     istringstream stream(line);
     while( stream>>word)
      //….
   }
2. stringstream提供的转换或格式化
   stringstream对象的一个最常用的用法是:需要在多种数据类型之间实现自动格式化使用该类类型。

抱歉!评论已关闭.