转自:
      
      
       
        http://blog.pfan.cn/aurora/18800.html
       
      
     
    
     
     
    
     
     
    
     
      
       
        当
       
      
      
       输入/输出的数据没有指定格式,它们都按缺省的格式输入/输出。然而,有时需要对数据
      
     
     
     
     
      
       格式进行控制。这时需利用ios类中定义的格式控制成员函数,通过调用它们来完成格式的设置。ios类的格式控制函数如下所示:
       
      
     
    
| long flags( ) const | 返回当前的格式标志。 | 
| long flays(long newflag) | 设置格式标志为newflag,返回旧的格式标志。 | 
| long setf(long bits) | 设置指定的格式标志位,返回旧的格式标志。 | 
| long setf(long bits,long field) | 将field指定的格式标志位置为bits,返回旧的格式标志。 | 
| long unsetf(long bits) | 清除bits指定的格式标志位,返回旧的格式标志。 | 
| long fill(char c) | 设置填充字符,缺省条件下是空格。 | 
| char fill( ) | 返回当前填充字符。 | 
| int precision(int val) | 设置精确度为val,控制输出浮点数的有效位,返回旧值。 | 
| int precision( ) | 返回旧的精确度值。 | 
| int width(int val) | 设置显示数据的宽度(域宽),返回旧的域宽。 | 
| int width( ) | 只返回当前域宽,缺省宽度为0。这时插入操作能按表示数 据的最小宽度显示数据。 | 
     
      
       
        预定义的操纵算子
        
       
       
        使用成员函数控制格式化输入输出时,每个函数调用需要写一条语句,尤其是它不能用在插入或提取运算符的表达式中,而使用操纵算子,则可以在插入和提取运算符的表达式中控制格式化输
       
       
        入和输出。在程序中使用操纵算字必须嵌入头文件
       
      
     
     
      
       iomanip.h
       
      
     
    
| dec | 十进制的输入输出 | 
| hex | 十六进制的输入输出 | 
| oct | 八进制的输入输出 | 
| ws | 提取空白字符 | 
| ends | 输出一个nul字符 | 
| endl | 输出一个换行字符,同时刷新流 | 
| flush | 刷新流 | 
| resetiosflags(long) | 请除特定的格式标志位 | 
| setiosflags(long) | 设置特定的格式标志位 | 
| setfill(char) | 设置填充字符 | 
| setprecision(int) | 设置输出浮点数的精确度 | 
| setw(int) | 设置域宽格式变量 | 
     
      
       
        错误处理
       
      
      
      
      
     
     
      
       
        
         在对一个流对象进行I/O操作时,可能会产生错误。当错误发生时,错误的性质被记录在ios类的一个数据成员中。
        
       
      
     
     
      
      
       
        ios类中定义的描述错误状态的常量:
       
      
     
    
| goodbit | 没有错误,正常状态 eofbit 到达流的结尾 | 
| failbit | I/O操作失败,清除状态字后,可以对流继续进行操作。 | 
| badbit | 试图进行非法操作,清除状态字后,流可能还可以使用。 | 
| hardfail | 致命错误,不可恢复的错误。 | 
    
     
      
       
       
        ostream类的成员函数
        
       
      
      
       流的其它成员函数可以从流中读取字符或字符串,对流进行无格式化的输入 输出操作,以及直接控制对流的I/O操作。
      
     
     
      
      
| 返回类型 | ios类的成员 | 描 述 | 
| ostream* | tie(ostream*) | 将当前流与指定的输出流连接起来。每当需要 读取当前流时,连接的流会自动刷新。C++流库已用cin.tie(cout)将输入流与输出流连接 起来。要取消与输出流的连接可采用is.tie(0) | 
| ostream* | tie( ) | 返回指向连接流的指针 | 
     
    
     
     
    
     
      
     
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
| 返回类型 | ostream类的成员 | 描 述 | 
| ostream& | put(char ch) | 向流中输出一个字符ch,不进行任何转换 | 
| ostream& | write(char*,int) | 向流中输出指定长度的字符串,不进行转换 | 
| ostream& | flush( ) | 刷新流,输出所有缓冲的但还未输出的数据 | 
| ostream& | seekp(streampos) | 移动流的当前指针到给定的绝对位置 | 
| ostream& | seekp(sereamoff,seek_dir) | 流的当前指针类似与文件的当前指针 | 
| streampos | teelp( ) | 返回流的当前指针的绝对位置 | 
     
      
       istream类的成员函数
      
     
    
| 返回类型 | istream类的成员 | 描 述 | 
| int | get( ) | 读取并返回一个字符 | 
| istream& | get(char&c) | 读取字符并存入c中 | 
| istream& | get(char*ptr,int len,char delim=”) | 读取指定的字符到缓冲区中,直到遇到指定的分界符为止,分界符不填入缓冲区。 | 
| istream& | getline(char*ptr,int len,char delim=”) | 与get(char*ptr,int len,chardelim =”) 类似,但将分界符填 入缓冲区。 | 
| istream& | putback( ) | 将最近读取的字符放回流中 | 
| istream& | read(char*,int) | 读取规定长度的字符串到缓冲区中 | 
| int | peek( ) | 返回流中下一个字符,但不移动文 件指针 | 
| istream& | seekg(streampos) | 移动当前指针到一绝对地址 | 
| istream& | seekg(streampos,seek_dir) | 移动当前指针到一相对地址 | 
| streampos | tellg( ) | 返回当前指针 | 
| istream& | ignore(int n=1,delim=EOF) | 跳过流中几个字符,或直到遇到指定的分界符为止 | 
     
      附:以16进制形式打印内存数据:
     
    
     
      #include <iostream>
      
      #include <iomanip>
      
      using namespace std;
     
    
     
      void foo( const void* buf, size_t len )
      
      {
      
      
      const unsigned char* p = (const unsigned char*)buf;
      
      for( size_t i=0; i<len; ++i )
      
      {
      
      
      cout << setfill(‘0’) << setw(2) << uppercase << hex << (unsigned)p[i] << ‘ ‘;
      
      }
      
      cout << endl;
      
      }
     
    
     
      int main( void )
      
      {
      
      
      char *test1 = “/x00/x01/x10/xFF”;
      
      foo( test1, 4 );
     
    
     
      double  test2 = 123.456;
      
      foo( &test2, 8 );
     
    
     
      return 0 ;
      
      };
     
    
     
      输出:
     
    
     
      00 01 10 FF
     
    
     
      77 BE 9F 1A 2F DD 5E 40
     
    
     
     
    
     
      补充(2008-11-06):
     
    
每一个iostream库对象都维护了一个格式状态(format state),它控制格式化操作的细节,比如整型值的进制基数或浮点数值的精度。C++为程序员提供了一组预定义的操纵符,可用来修改一个对象的格式状态。
操纵符被应用在流对象上的方式,就好像它们是数据一样。但是,操纵符不导致读写数据,而是修改流对象的内部状态。例如,缺省情况下,true值的bool对象被写成整数值1:
#include <iostream>
      int main()
      
      {
      
      
      bool illustrate = true;;
      
      cout << “bool object illustrate set to true: ”
      
      << illustrate << ‘/n’;
      
      }
为了修改cout,使它能够把illustrate显示为true,我们应用boolalpha操纵符:
#include <iostream>
      int main()
      
      {
      
      
      bool illustrate = true;;
      
      cout << “bool object illustrate set to true: “;
      // 改变cout的状态
      
      // 用字符串true和false输出bool值
      
      cout << boolalpha;
      
      cout << illustrate << ‘/n’;
      
      }
因为操纵符被应用之后,仍然返回原来被应用的流对象,所以我们可以把它的应用与数据的应用连接起来(或者与其他操纵符的应用连接起来)。下面是重写之后的小程序,它混合了数据和操纵符:
#include <iostream>
      int main()
      
      {
      
      
      bool illustrate = true;
      
      cout << “bool object illustrate: ”
      
      << illustrate
      
      << “/nwith boolalpha applied: ”
      
      << boolalpha << illustrate << ‘/n’;
      // …
      
      }
      像这样,把操纵符和数据混合起来容易产生误导作用。应用操纵符之后,不只改变了后面输出值的表示形式,而且修改了ostream的内部格式状态。在我们的例子中,整个程序的余下部分都将把bool值显示为true或false。
      
      为了消除对cout的修改,我们必须应用noboolalpha操纵符:
      cout << boolalpha   // 设置cout的内部状态
      
      << illustrate
      
      << noboolalpha // 解除cout内部状态
      我们将会看到,许多操纵符都有类似的“设置/消除(set/unset)”对 。
      
      缺省情况下,算术值以十进制形式被读写。程序员可以通过使用hex、oct和dec操纵符,把整数值的进制基数改为八进制或十六进制,或改回十进制(浮点值的表示不受影响)。例如:
      #include <iostream>
      
      int main()
      
      {
      
      
      int ival = 16;
      
      double dval = 16.0;
      cout << “ival: ” << ival
      
      << ” oct set: ” << oct << ival << “/n”;
      cout << “dval: ” << dval
      
      << ” hex set: ” << hex << dval << “/n”;
      cout << “ival: ” << ival
      
      << ” dec set: ” << dec << ival << “/n”;
      
      }
编译并执行程序,产生下列输出:
      ival: 16 oct set: 20
      
      dval: 16 hex set: 16
      
      ival: 10 dec set: 16
      
      我们这个程序的一个问题是,我们在看到一个值的时候无法知道它的进制基数。例如,20是真正的20,还是16的八进制表示?操纵符showbase可以让一个整数值在输出时指明它的基数,形式如下:
      
      1.0x开头表明是十六进制数(如果希望显示为大写字母,则可以应用uppercase操纵符;为了转回小写的x,我们可以应用nouppercase操纵符)。
      
      2.以0开头表示八进制数。
      
      3.没有任何前导字符,表示十进制数。
      
      下面是用showbase改写过的程序:
      #include <iostream>
      
      int main()
      
      {
      
      
      int ival = 16;
      
      double dval = 16.0;
cout << showbase;
      cout << “ival: ” << ival
      
      << ” oct set: ” << oct << ival << “/n”;
      cout << “dval: ” << dval
      
      << ” hex set: ” << hex << dval << “/n”;
      cout << “ival: ” << ival << ” dec set: ”
      
      << dec << ival << “/n”;
      cout << noshowbase;
      
      }
下面是修改后的输出:
      ival: 16 oct set: 020
      
      dval: 16 hex set: 16
      
      ival: 0x10 dec set: 16
      noshowcase操纵符重新设置cout,使它不再显示整数值的进制基数。
      
      缺省情况下,浮点值有6位的精度。这个值可以用成员函数precision(int)或流操纵符setprecision()来修改(若使用后者,则必须包含iomanip头文件)。precision()返回当前的精度值。例如:
      #include <iostream>
      
      #include <iomanip>
      
      #include <math.h>
      int main()
      
      {
      
      
      cout << “Precision: ”
      
      << cout.precision() << endl
      
      << sqrt(2.0) << endl;
      cout.precision(12);
      
      cout << “/nPrecision: ”
      
      << cout.precision() << endl
      
      << sqrt(2.0) << endl;
      cout << “/nPrecision: ” << setprecision(3)
      
      << cout.precision() << endl
      
      << sqrt(2.0) << endl;
      return 0;
      
      }
编译并执行程序,产生以下输出:
      Precision: 6
      
      1.41421
      Precision: 12
      
      1.41421356237
      Precision: 3
      
      1.41
      带有一个实参的操纵符,比如前面见到的setprecision()和setw(),要求包含iomanip头文件:
      
      #include <iomanip>
      
      我们的例子没有说明setprecision()的两个更深入的方面:1)整数值不受影响,2)浮点值被四舍五入而不是被截取。因此当精度为4时,3.14159变成3.142,精度为3时变成3.14。
      
      缺省情况下,当小数部分为0时,不显示小数点。例如:
      
      cout << 10.00
      
      输出为
      
      10
      
      为了强制显示小数点,我们使用showpoint操纵符:
      cout << showpoint
      
      << 10.0
      
      << noshowpoint << ‘/n’;
      noshowpoint操纵符重新设置缺省行为。
      
      缺省情况下,浮点值以定点小数法显示。为了改变为科学计数法,我们使用scientific操纵符。为了改回到定点小数法,我们使用fixed操纵符:
      cout << “scientific: ” << scientific
      
      << 10.0
      
      << “fixed decimal: ” << fixed
      
      << 10.0 << ‘/n’;
这产生
      scientific: 1.0e+01
      
      fixed decimal: 10
      如果希望把‘e’输出为‘E’,我们可以使用uppercase操纵符。要转回小写字母,我们使用nouppercase操纵符。(uppercase操纵符不会使所有字母字符都显示为大写!)。
      
      缺省情况下,重载的输入操作符跳过空白字符(空格、制表符、换行符、走纸、回车)。已知序列
      a b c
      
      d
循环
      char ch;
      
      while ( cin >> ch )
      
      // …
执行四次,以读入从a到d的四个字符,跳过中间的空格、可能的制表符和换行符。操纵符noskipws使输入操作符不跳过空白字符:
      char ch;
      
      cin >> noskipws;
      
      while ( cin >> ch )
      
      // …
      
      cin >> skipws;
      现在while循环需要迭代七次,才能读入字符a到d。为了转回到缺省行为,我们在cin上应用操纵符skipws。
      
      当我们写
      
      cout << “please enter a value: “;
      
      文字字符串被存储在与cout相关联的缓冲区中。有许多种情况可以引起缓冲区被刷新——即,清空——在我们的例子中,也就是将缓冲区写到标准输出上:
      
      1.缓冲区可能会满,在这种情况下,它必须被刷新,以便读取后面的值。
      
      2.我们可通过显式地使用flush、ends或endl操纵符来刷新缓冲区。
      // 清空缓冲区
      
      cout << “hi!” << flush;
      // 插入一个空字符然后刷新缓冲区
      
      char ch[2]; ch[0] = ‘a’; ch[1] = ‘b’;
      
      cout << ch << ends;
      // 插入一个换行符然后刷新缓冲区
      
      cout << “hi!” << endl;
      3.unitbuf,一个内部的流状态变量,若它被设置,则每次输出操作后都会清空缓冲区。
      
      4.一个ostream对象可以被捆绑到一个istream上,在这种情况下,当istream从输入流读取数据时,ostream的缓冲区就会被刷新。cout被预定义为“捆绑”在cin上:
      
      cin.tie( &cout );
      
      语句
      
      cin >> ival;
      
      使得与cout相关联的缓冲区被刷新。
      
      一个ostream对象一次只能被捆绑到一个istream对象上,为了打破现有的捆绑,我们可以传递一个实参0。例如:
      istream is;
      
      ostream new_os;
// …
      // tie() 返回现有的捆绑
      
      ostream *old_tie = is.tie();
      is.tie( 0 ); // 打破现有的捆绑
      
      is.tie( &new_os ); // 设置新的捆绑
// …
      is.tie( 0 ); // 打破现有的捆绑
      
      is.tie( old_tie ); // 重新建立原来的捆绑
我们可以用setw()操纵符来控制数字或字符串值的宽度。例如程序
      #include <iostream>
      
      #include <iomanip>
      int main()
      
      {
      
      
      int ival = 16;
      
      double dval = 3.14159;
      cout << “ival: ” << setw(12) << ival << ‘/n’
      
      << “dval: ” << setw(12) << dval << ‘/n’;
      
      }
产生以下输出:
      ival:       16
      
      dval:     3.14159
      第二个setw()是必需的,因为不像其他操纵符,setw()不修改ostream对象的格式状态。
      
      要想使输出的值左对齐,我们可以应用left操纵符(通过right操纵符可以重新设回到缺省状态)。如果我们希望产生
      16
      
      –   3
      我们可以应用internal操纵符,它使得正负符号左对齐,而值右对齐,中间添加空格。如果希望用其他字符填充中间的空白,则可以应用setfill()操纵符。
      
      cout << setw(6) << setfill(‘%’) << 100 << endl;
      
      产生
      
      %%%100
      
      预定义的所有操纵符都被列在表20.1中。
      操 纵 符 含     义
      
      boolalpha 把true 和 false 表示为字符串
      
      *noboolalpha 把true 和 false 表示为0、1
      showbase 产生前缀,指示数值的进制基数
      
      *noshowbase 不产生进制基数前缀
      showpoint 总是显示小数点
      
      *noshowpoint 只有当小数部分存在时才显示小数点
      
      Showpos 在非负数值中显示 +
      
      *noshowpos 在非负数值中不显示 +
      *skipws 输入操作符跳过空白字符
      
      noskipws 输入操作符不跳过空白字符
      uppercase 在十六进制下显示 0X , 科学计数法中显示E
      
      *nouppercase 在十六进制下显示 0x, 科学计数法中显示e
      *dec 以十进制显示
      
      hex 以十六进制显示
      
      oct 以八进制显示
      left 将填充字符加到数值的右边
      
      right 将填充字符加到数值的左边
      续表
      
      操 纵 符 含     义
      
      Internal 将填充字符加到符号和数值的中间
      *fixed 以小数形式显示浮点数
      
      scientific 以科学计数法形式显示浮点数
      flush 刷新ostream缓冲区
      
      ends 插入空字符,然后刷新ostream缓冲区
      
      endl 插入换行符,然后刷新ostream缓冲区
      
      ws “吃掉” 空白字符
      // 以下这些要求 #include <iomanip>
      
      setfill( ch ) 用ch填充空白字符
      
      setprecision( n ) 将浮点精度设置为 n
      
      setw( w ) 按照w个字符来读或者写数值
      
      setbase( b ) 以进制基数 b 输出整数值
      
      * 表示缺省的流状态
iostream库是强类型的。例如,试图从一个ostream读数据,或者写数据到一个istream,都会在编译时刻被捕获到,并标记为类型违例。例如,已知下列声明
      #include <iostream>
      
      #include <fstream>
      
      class Screen;
      extern istream& operator>>( istream&, const Screen& );
      
      extern void print( ostream& );
      
      ifstream inFile;
下面的两条语句都将导致编译时刻类型违例:
      int main()
      
      {
      
      
      Screen myScreen;
      // 错误:期望一个 ostream&
      
      print( cin >> myScreen );
      // 错误:期望 >> operator
      
      inFile << “error: output operator”;
      
      }
      
     
 
