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

深入详解C++ I/O

2014年01月28日 ⁄ 综合 ⁄ 共 11568字 ⁄ 字号 评论关闭

                                    C++ I/O深入详解

<iostream>库自动定义了一些标准对象:
cout, ostream类的一个对象,可以将数据显示在标准输出设备上.
cerr, ostream类的另一个对象,它无缓冲地向标准错误输出设备输出数据.
clog, 类似cerr,但是它使用缓冲输出.
cin, istream类的一个对象,它用于从标准输入设备读取数据.
<fstream>库允许编程人员利用ifstream和ofstream类进行文件输入和输出. 一些C++ I/O流(精度,判断等)的行为可以通过操作不同的标志来修改。

函数列表:
Constructors 构造器
bad() 如果出现错误则返回true
clear() 清除状态标志
close() 关闭一个流
eof() 如果处于文件结尾处则返回true
fail() 如果出现错误则返回true
fill() 控制默认填充字符
flags() 操作flags
flush() 清空缓冲区
gcount() 返回读取的最后一次输入的字符数
get() 读取字符
getline() 读取一行字符
good() 如果没有出现过错误则返回true
ignore() 读取字符并忽略指定字符
open() 创建一个输入流
peek() 检查下一个输入的字符
precision() 设置精度
put() 写字符
putback() 返回字符给一个流
rdstate() 返回流的状态
read() 读取字条符
seekg() 在一个输入流中进行随机访问
seekp() 在一个输出流中进行随机访问
setf() 设置格式标志
sync_with_stdio() 同标准I/O同步
tellg() 使用输入流读取流指针
tellp() 使用输出流读取流指针
unsetf() 清除格式标志
width() 操作域宽度
write() 写字符

/////////////////////////////////////////////////////////////////////////////////////////////

构造器
语法:
  fstream( const char* szName, int nMode, int nProt = filebuf::openprot );
  ifstream( const char* szName, int nMode = ios::in, int nProt = filebuf::openprot );
  ofstream( const char* szName, int nMode = ios::out, int nProt = filebuf::openprot );
参数说明:
1.szName  要打开的文件名 ;
2.nMode   要打开文件的方式,有以下几种方式:
          ios::app:   以追加的方式打开文件
          ios::ate:   文件打开后定位到文件尾,ios:app就包含有此属性
          ios::binary:  以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文
          ios::in:    打开文件进行读操作
          ios::out:   打开文件进行写操作
          ios::nocreate: 不建立文件,所以文件不存在时打开失败 
          ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败
          ios::trunc  打开文件时,如果该文件已存在,则先将该文件删除。此列举符可以同ios::out一起使用,但不可同ios::ate、i os::app和ios::in一起使用
mode的符号常量可以“|”组合在一起,如  ios::in|ios::binary表示以只读方式打开二进制文件。
    在实际应用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。
3.nProt   文件保护方式,有以下几种方式:
          filebuf::sh_compat   兼容共享方式
          filebuf::sh_none   独占,不共享
          filebuf::sh_read   允许读共享
          filebuf::sh_write   允许写共享
示例:ifstream fip("binfile.dat",ios::in|ios::binary);

int is_open() const;
功能:判断与流相关的文件是否打开。
bad
语法:
  int bad() const;
如果当前的流发生致命的错误,bad()函数返回非零值。
int fail() const;
如果当前流发生错误fail()函数返回非零值 。
int good() const;
如果当前流没有发生错误,函数good()返回非零值 。
void clear( int nState = 0 );
函数clear()清除与当前流相关联的标志。默认标志是goodbit=0它清除所有标志.否则只有指定的标志被清除。
nState可能的取值:
ios::goodbit   清除所有标志
ios::eofbit    End of file reached.(文件EOF标志)
ios::failbit   失败标志
ios::badbit    A severe I/O error(严重的I/O错误标志)

int rdstate() const;
功能:返回当前已设立所有标志。
可能的返回值:
ios::goodbit   No error condition.
ios::eofbit   End of file reached.
ios::failbit   A possibly recoverable formatting or conversion error.
ios::badbit   A severe I/O error or unknown state.

void close();
Tclose()函数关闭相关的文件流。
int eof()const;
如果到达相关联的输入文件的末尾,eof()函数返回非零值。例如:
   char ch;
    ifstream fin( "temp.txt" );
    while( !fin.eof() ) {
      fin >> ch;
      cout << ch;
    }
    fin.close();

  char fill();
  char fill( char ch );
函数fill()可以返回当前填充字符,或者设置当前填充字符为ch 。填充字符被定义为用来填充字符,默认的填充字符是空格。
char fill()const;
  char fill( char ch );
函数fill()可以返回当前填充字符,或者设置当前填充字符为ch 。填充字符被定义为用来填充字符,当一个数字比较指定宽度T小时。默认的填充字符是空格。
setfill
SMANIP( int ) setfill( int nFill );(#include <iomanip.h>)
功能:设置当前填充字符为nFill 。

比较setw与setfill.
setw控制符只对后面紧跟的起作用,而setfill控制符一旦设定,就会对后面一直起作用,直到你重新设置。
我给你举个例子,看下面这段程序:
#include <iostream>
#include <iomanip>
using namespace std;
void main()
{
     cout<<setw(8)<<setfill('*')<<123<<endl;
     cout<<setw(8)<<456<<endl;
}
输出结果是:
*****123
*****456
如果只想填满紧跟后面的,必须重新设置:
#include <iostream>
#include <iomanip>
using namespace std;
void main()
{
   cout<<setw(8)<<setfill('*')<<123<<endl;
   cout<<setw(8)<<setfill(' ')<<456<<endl;
}
注意:重新设置的填充符是空格
这样运行结果是:
*****123
     456

fmtflags flags();
  fmtflags flags( fmtflags f );
flags()函数或者返回当前流的格式标志,或者为当前流设置标志为f。

ostream& flush;//flush做为操作符使用
ostream& flush();//flush做为函数使用
1.flush()函数可以引起当把前流的缓冲区写出到附属设备中去。这个函数对于打印调试信息很用处,因为当程序有机会把缓冲区内容写出到屏幕之前,程序会被中断。灵活地使用flush()可以保证你所有的调试状态都实在的打印出来。
2.endl控制符和’ /n’换行符都可以将光标移动到输出设备中下一行的开头处。但是,endl控制符还有另外的用途。
当程序向输出设备中输出数据时,输出的数据先被存放在计算机缓冲区(Buffer)内。当缓冲区存满时,这些数据才真正地输出到输出设备。但是,如果输出的字符序列中出现了 endl控制符,那么缓冲区内的所有数据将立即输出到输出设备,而无论缓冲区是否已经存满。因此,endl控制符的作用是将光标移动到输出设备中下一行开头处,并且清空缓冲区。很有可能出现在程序终止时,并没有输出所有的输出数据的情况。这是因为在程序终止时,缓冲区并不一定是满的,所以也就没有将缓冲区中的数据写到输出设备。
    在C++中,可以使用flush函数来清空缓冲区,即使缓冲区中的数据不是满的。与endl控制符不同的是,flush函数并不是把光标移到下一行的开头处。与endl一样,flush可以作为控制符使用。在这种情况下,flush使用在输出语句中,并不加括号。例如,下面的语句将数据从缓冲区写到标准输出设备:cout<<flush;
例:考虑下面的语句,其中num是int类型变量:
      cout<<”enter an integer:”;
      cin>>num;
      cout<<endl;
第一行语句输出文字:“enter an integer:”。在输出这一行文字后,光标停留在冒号后面的位置上。注意,第1行语句的输出首先被送到缓冲区中。如果缓冲区中的数据没有存满,那么这行提示文字就不会显示出来。这时用户也就不知道下一步应该做什么。可以在第1行语句后面使用endl控制符。但是如果这样做,在输出这行文字后,光标将被移到下一行的开头处,用户也就必须在下一行中输入数字。而这样做并不是最恰当的。还可以使用下面的语句替换掉1行语句:
     cout<<”enter an integer:”<<flush;
在这种情况下,文字行“enter an integer:”,即使在缓冲区数据没有存满时也会立即被输出到标准输出设备上。而且,在输出这行文本后,光标将停留在分号的下一个位置上。用户将在分号后面输入数字。

streamsize gcount();
函数gcount()被用于输入流,并返回上一次输入操作被读入的字符的数目。
示例:
#include <iostream>
using namespace std;
void main( )
{
   cout << "Type the letter 'a': ";
   ws( cin );//跳过空白符
   char c[10];
   cin.get( &c[0],9 );
   cout << c << endl;
   cout << cin.gcount( ) << endl;
}
输出结果:
Type the letter 'a': affjojleojfljwio
affjojle
8

随便讲一下上面例题中出现的ws.它有两种用法:
1.template class<E, T>
    basic_istream<E, T>& ws(basic_istream<E, T> is);//作为函数
2.istream& ws;//作为操作符
功能:当输入遇到空格时跳过空格字符而不读取。cin>>ws>>c只会吃掉输入字串前面的空格,假如输入字串Hello world!前有20个空格,输出时空格将不复存在。
示例:
#include<strstrea.h>
void main()
{
   char a[]="  38,   46,55   ,78.42,77,60,93@";
   cout<<a<<endl;//输出a字符串
   istrstream sin(a);//定义一个输入字符串流sin,使用的字符数组为a
   char ch;
   int x;
   while(ch!='@'){
    //使用‘@‘字符作为字符串流结束标志
       sin>>ws>>x>>ws;//从流中读入一个整数,并使用操作符ws读取
       //一个整数前后的空白字符
       cout<<x<<" ";//输出x的值并后跟一个空格
       sin.get(ch);//从sin流中读入一个字符
   }
   cout<<endl;
 }
输出结果:
  38,   46,55   ,78.42,77,60,93@
38 46 55 78 42 77 60 93

  int get();
  istream &get( char &ch );
  istream &get( char *buffer, streamsize num );
  istream &get( char *buffer, streamsize num, char delim='/n' );
  istream &get( streambuf &buffer );
  istream &get( streambuf &buffer, char delim='/n' );
get()函数被用于输入流,和以下这些:
1.读入一个字符并返回它的值,
2.读入一个字符并把它存储在ch,
3.读取字符到buffer直到num - 1个字符被读入, 或者碰到EOF或换行标志,
4.读取字符到buffer直到已读入num - 1 个字符,或者碰到EOF或delim(delim直到下一次不会被读取),
5.读取字符到buffer中,直到碰到换行或EOF,
6.读取字符到buffer中,直到碰到换行,EOF或delim。(相反, delim直到下一个get()不会被读取 ).
示例:
#include <iostream.h>
#include <string.h>
#include <fstream.h>

void main()
{
 ofstream fop("test.dat");
 char name[20];                     //存储姓名
 unsigned id;                       //存储学号
 int age;                           //存储年龄
 char address[80];                  //存储地址
 char yes[2];                       //是否继续存储
 do {
  cout << "请输入姓名: ";
  cin >> name;
  cout << "请输入学号: ";
  cin >> id;
  cout << "请输入年龄: ";
  cin >> age;
  cout << "请输入地址: ";
  cin.ignore();
  cin.getline(address,80);
  fop << name <<"  "<< id <<"  "<< age <<"  "<< address << endl;
  flush(cout);                        //冲刷缓冲区,使数据显示正确
  cout << "是否继续输入数据?(Y/N): ";
  cin >> yes;
 } while (!strcmp(strupr(yes),"Y"));     //strupr可以将字符串的内容改为大写字母
 fop.close();
 cout << "…输入结束…/n数据读取如下: /n";
 char ch;
 ifstream fip("test.dat");
 while (fip.get(ch))
  cout << ch;
 cout << "/n…打印结束…/n";
 fip.close();
}
输出结果:
请输入姓名: 李强
请输入学号: 12
请输入年龄: 21
请输入地址: 北京
是否继续输入数据?(Y/N): Y
请输入姓名: 王明
请输入学号: 5
请输入年龄: 22
请输入地址: 上海
是否继续输入数据?(Y/N): n
…输入结束…
数据读取如下:
李强  12  21  北京
王明  5  22  上海

…打印结束…
  
istream::getline
istream& getline( char* pch, int nCount, char delim = '/n' );
istream& getline( unsigned char* puch, int nCount, char delim = '/n' );
istream& getline( signed char* psch, int nCount, char delim = '/n' );
getline()函数用于输入流,读取字符到buffer中,直到下列情况发生:
num - 1个字符已经读入 (第num个字符
碰到一个换行标志,
碰到一个EOF,
或者,任意地读入,直到读到字符delim。delim字符不会被放入buffer中
 
    比较istream &get( char *buffer, streamsize num, char delim='/n' )与istream& getline( char* pch, int nCount, char delim = '/n' )的区别:
    函数get当遇到分隔符后,停止获取,并将分隔符留在输入流中,函数getline当遇到分隔符后,停止获取,但会将分隔符从输入流中取出。
示例:
          ifstream in("c://hello.txt");
1         char str[10];
2         while(in.get(str,10))
3         {
4               cout<<str<<'/n';
5                in.get();
6         }
7         in.close();
8         ifstream in1("c://hello.txt");
9         while(in1.getline(str,10))
10                cout<<str<<'/n';     
11         in1.close();
注意2~~5行以及9~~10行之间代码的差异,第4行代码在输出str后,在第5行代码使用第1个get读取一个字符并丢弃。这是因为,第3个get函数读取数据遇到分隔符时,停止读取并将分隔符留在输入流中,使用第1个版本的get函数读取一个字符并丢弃是为了将分隔符从输入流中取出,保证下一次循环执行第3个版本的get函数时,能够继续读取下一行数据。但是,使用getline函数不必向第5行代码那样,将读取分隔符取出并抛弃。这是因为getline函数读取数据遇到分隔符时,停止读取并将分隔符取出并直接抛弃(不存入str中)。

 

istream &ignore( streamsize num=1, int delim=EOF );
ignore()函数用于输入流。它读入字符,直到已经读了num 个字符(默认为1)或是直到字符delim 被读入(默认为EOF).
Cin.ignore()方法cin.ignore(5, 'c') 的是从输入流(cin)中提取字符,提取的字符被忽略(ignore),不被使用。每抛弃一个字符,它都要计数和比较字符:如果计数值达到5或者被抛弃的字符是'c',则cin.ignore()   函数执行终止;否则,它继续等待。  它的一个常用功能就是用来清除以回车结束的输入缓冲区的内容,消除上一次输入对下一次输入的影响。比如可以这么用:cin.ignore(1024, '/n');,通常把第一个参数设置得足够大,这样实际上总是只有第二个参数'/n'起作用,所以这一句就是把回车(包括回车)之前的所以字符从输入缓冲(流)中清除出去。
示例:
#include <fstream.h>
void main()
{
   // 假设test.txt中已经存有"Hello World"这一内容
   ifstream File("test.txt");
   static char arr[10];
   // 假如一直没有遇到字符"l",则向前定位直到跳过6个字符
   // 而如果期间遇到"l",则停止向前,定位在该处
   File.ignore(6,'l');
   File.read(arr,10);
   cout << arr << endl; // 它将显示"lo World!"
   File.close();
}
输出结果:
        lo World!

void open( const char *filename);
  void open( const char *filename, openmode mode );

 

函数open()用于文件流。它打开filename 并将其与当前的流相关联。可以选择的模式有:

模式 含义
ios::app 添加输出
ios::ate 当已打开时寻找到EOF
ios::binary 以二进制模式打开文件
ios::in 为读取打开文件
ios::out 为写入打开文件
ios::trunc 覆盖存在的文件

如果open()失败,当用于一个布尔表达式中时,作为结果的流会给出对错误的评估。例如:

  ifstream inputStream("file.txt");
  if( !inputStream ) {
    cerr << "Error opening input stream" << endl;
    return;
  }

int peek();
函数peek()用于输入流中,并返回在流中的下一个字符或如果是处于输入的文件的结尾处返回EOF。peek()不会把字符从流中移除。
示例:
#include <fstream>
using namespace std;
void main(void)
{
  char ch, temp;
  while (cin.get(ch))
  { 
     temp = cin.peek();
     cout<<temp;
  }
}
输出结果:
abc
bc
defg
defg
分析:为什么第一组数据abc bc中只输出bc,而a没有输出呢?因为get(ch)把abc插入流中当前流位置在a处temp = cin.peek() 通过.peek() 把当前流的下一字符的副本即为b返回给temp所以输出b,然后通过循环 流位置在b处,再通过.peek()返回流的下一字符c给temp所以输出c。

int precision( int np );
int precision() const;
precision()函数设置或返回当前要被显示的浮点变量的位数。例如,下面的代码:
    float num = 314.15926535;
    cout.precision( 5 );
    cout << num;
displays
    314.16

ostream &put( char ch );
函数put()用于输出流,并把字符ch写入流中
示例:
#include <fstream>
using namespace std;
void main(void)
{
  char ch;
  ifstream in("test.txt");//test.txt中的内容为:hou are you?
                          //                   Fine,thank you!
  while (in.get(ch))
  { 
 cout.put(ch);
  }
}
输出结果:
hou are you?
Fine,thank you!

putback
语法:
  istream &putback( char ch );
  putback()函数用于输入流,并且返回以前读的字符ch到输入流中.
示例:
// istream putback
#include <iostream>
using namespace std;
void main ()
{
  char c;
  int n;
  char str[256];
  cout << "Enter a number or a word: ";
  c = cin.get();
  if ( (c >= '0') && (c<= '9'))
  {
    cin.putback (c);
    cin >> n;
    cout << "You have entered number " << n << endl;
  }
  else
  {
    cin.putback (c);
    cin >> str;
    cout << " You have entered word " << str << endl;
  }
}

istream &read( char *buffer, streamsize num );
函数read()用于输入流,在将字符放入buffer 之前从流中读取num 个字节。如果碰到EOF,read()中止,丢弃不论多少个字节已经放入。例如:
    struct {
      int height;
      int width;
    } rectangle;
   
    input_file.read( (char *)(&rectangle), sizeof(rectangle) );
    if( input_file.bad() ) {
      cerr << "Error reading data" << endl;
      exit( 0 );
    }

istream &seekg( off_type offset, ios::seekdir origin );
  istream &seekg( pos_type position );
函数seekg()用于输入流,并且它将重新设置"get"指针到当前流的从origin偏移offset个字节的位置上,或是置"get"指针在position位置。
long setf( long lFlags );
long setf( long lFlags, long lMask );
函数setf()设置当前流的格式化标志为lflags。可选标志lMask只允许lflags标志和lMask标志都被设置。返回值是前面设置的标志。
例如:
    int number = 0x3FF;
    cout.setf( ios::dec );
    cout << "Decimal: " << number << endl;
    cout.unsetf( ios::dec );
    cout.setf( ios::hex );
    cout << "Hexadecimal: " << number << endl;
提示,上面的代码和下面的代码的功能是一致的:
    int number = 0x3FF;
    cout << "Decimal: " << number << endl << hex << "Hexadecimal: " << number << dec << endl
long unsetf( long lFlags );
函数unsetf()用于清除与当前流相关的给定的标志lflags。返回值是前面设置的标志。

static bool sync_with_stdio( bool sync=true );
sync_with_stdio()函数有打开或关闭使用C++风格I/O系统混合C风格的I/O系统的功能。
pos_type tellg();
tellg()函数用于输入流,并返回流中"get"指针的当前位置。
pos_type tellp();

 

tellp()函数用于输出流中,并返回在流中当前"put"指针的位置。 例如,下面的代码显示了当一个文件指针写入一个流的时候的情形:

  string s("In Xanadu did Kubla Khan...");

  ofstream fout("output.txt");

  for( int i=0; i < s.length(); i++ ) {
    cout << "File pointer: " << fout.tellp();
    fout.put( s[i] );
    cout << " " << s[i] << endl;
  }

  fout.close();

int width();
  int width( int w );

 

函数 width()返回当前的宽度。可选择参数w用于设定宽度大小。宽度是指每一次输出中显示的字符的最小数目。例如:

    cout.width( 5 );
    cout << "2";

displays

        2

(在一个'2'的后面紧跟着四个空格)
ostream &write( const char *buffer, streamsize num );
write()函数用于输出流,从buffer中写num个字节到当前输出流中。

 

 

 

 

抱歉!评论已关闭.