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

IO 流综述

2012年09月12日 ⁄ 综合 ⁄ 共 4864字 ⁄ 字号 评论关闭

首先看看流中各个类的继承情况:

 

 

看了图以后各个类的继承情况就了解清楚了。。。。

io对象不可复制:

   因此在对io对象操作时,尤其是将io对象作为参数或返回类型时,都要将io对象使用引用。

例 ostream & print(ostream &os)

{

os<<"hello"<<endl;

}

还有就是参数不能用const,原因是因为在对io流对象操作时可能会改变流的状态,下面会详细的谈到。。。

io条件状态

io条件状态有很多选项,

strm::iostate 及其相关的整形名,由各个iostream类对象,用于定义条件状态

strm::badbit   用于指出被破环的流

strm::failbit   用于指出失败的流

strm::eofbit 用于指出流已经到达文件结尾

s.eof()   如果设置了流s的eofbit,则该函数返回true

s.fail()   如果设置了流s的failbit,则该函数返回true

s.bad() 如果设置了流s的badbit,则该函数返回true

s.good() 如果流处于有效状态,则该函数则返回true

s.clear() 将流s中的所有状态重设为有效状态

s.clear(flag) 将流中的某个指定条件状态设置为有效状态

s.setstate(flat) 给s添加指定条件。flag的类型是strm::iostate

s.rdstate() 返回流s的当前条件,返回值类型为strm::iostate

下面看一个综合的例子:

#include<iostream>
#include<fstream>
#include<sstream>
#include<stdio.h>
using namespace std;
istream& get(istream& in)
{int ival;
while(in>>ival,!in.eof())
{
   if(in.bad())
   throw runtime_error("istream corrupt");
   if(in.fail())
   {
    cerr<<"bad data,try again";
    in.clear();
   // in.ignore(200,'/n');

//fflush(stdin);
    continue;
   }
   cout<<ival<<" "<<endl;

}
in.clear();
return in;
}
void main()
{
    get(cin);
}

在这个例子运行的时候,如果是输入整形数据的时候,一切都正常。。。

输入一个马上就打印出来,

文件结束符在windows底下是ctrl+z(好像不是很好用,不是容易成功)

在linux底下是ctrl+d(已经试验成功)

所以大家可以到linux下试验类似的程序

但是如过输入非法字符就会无限循环

下面我们就分析一下为什么?

在cin>> <int/float>时 如果我们输入一个字符 就会导致刷屏的结果 这是因为非数字字符无法被cin接收而一直停留在缓冲区,导致下一次cin时直接从缓存读数 但字符无法读取结果导致无限循环 这被很多人认为成库的bug

解决方法:

1> 在cin>> <int/float>后加cin.ignore(); cin.clear();

cin.ignore()方法cin.ignore( 5, 'c' ) 的是从输入流(cin)中提取字符,提取的字符被忽略(ignore),不被使用。每抛弃一个字符,它都要计数和比较字符:如果计数值达到5或者被抛弃的字符是'c',则cin.ignore() 函数执行终止;否则,它继续等待。 它的一个常用功能就是用来清除以回车结束的输入缓冲区的内容,消除上一次输入对下一次输入的影响。比如可以这么用:cin.ignore( 1024, '/n' );,通常把第一个参数设置得足够大,这样实际上总是只有第二个参数 '/n' 起作用,所以这一句就是把回车(包括回车)之前的所以字符从输入缓冲(流)中清除出去。

cin.clear用法如果输入发生错误发生,那么流状态既被标记为错误,你必须清除这些错误状态,以使你的程序能正确适当地继续运行。要清除错误状态,需使用clear()函数。此函数带一个参数,它是你将要设为当前状态的标志值。,只要将ios::goodbit作为实参。

2> 在cin>> <int/float>后加fflush(stdin);(需要stdio.h) fflush(stdin)刷新标准输入缓冲区

 

io缓冲区的刷新

输出缓冲区的刷新

cout<<"hello"<<flush;//flushs the buffer,adds no data

cout<<"hello"<<ends; //insert a null,then flush the buffer

cout<<"hello"<<endl;//insert a newline,then flush the buffer

unitbuf操作符

如果需要刷新所有输出,最好使用unitbuf操作符,这个操作符

每次执行完写操作都会刷新流:

cout<<unitbuf<<"hello"<<nounitbuf;

nounitbuf操作符将流回复为使用正常的,有系统管理的缓冲区刷新方式

将输入和输出绑在一起:

当输入流和输出流绑在一起是,任何读输入流的尝试都将首先刷新其输出流缓冲区

cin.tie(&cout);

cin.tie(0);//break tie to cout

cin.tie(&cerr);

cin.break(0);//break tie to cerr

文件的输入和输出

看下面的例子:

#include<iostream>
#include<sstream>
#include<fstream>
using namespace std;
istream& get(istream& in)
{
char ival;
while((in>>ival,!in.eof()))
{

   if(in.bad())
   throw runtime_error("ifstream corrupt");
     if(in.fail())
   {

    cerr<<"bad data,try again";
    in.clear();
    in.ignore(200,'/n');
    continue;

   }
   cout<<ival<<" ";

}
in.clear();
return in;
}
int main()
{
string filename;
cout<<"enter the file name:"<<endl;
cin>>filename;
ifstream inFile(filename.c_str());
cout<<filename.c_str()<<endl;
if(!inFile)
{
   cerr<<"error:can not open input file:"
    <<filename<<endl;
   return -1;
}
get(inFile);
return 0;
}

假设你输入的文件的是正确的,且里面有内容

该程序就会读取里面的内容

文件打开的模式:

in 打开文件做读操作

out 打开文件做写操作

app 在每次写之前找到文件尾

ate 打开文件后立即将文件定位在文件尾

trunc 打开文件时清空已存在的流

binary 以二进制模式进行io操作

对同一个文件作输入和输出运算,这时文件不会清空

fstream inout("filename",fstream::in|fstream::out);

模式是文件的模式,而不是流的属性

ofstream outfile;

outfile.open("s",ofstream::out);

outfile.close();

outfile.open("n",ofstream::app);

outfile.close();

outfile.open("out");

最后一次打开文件时,没有加任何模式,这时默认的是以out模式打开文件的

这就意味着将文件打开时文件里内容被清空

下面是一个打开并检查输入文件的典型程序

ifstream& open_file(ifstream &in,const string& file)

{

in.close();

in.clear();

in.open(file.c_str());

return in;

}

由于不知道in的状态,首先将其设置为有效状态

#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
using namespace std;
void process(string);
int main()
{
vector<string>files;
string filename,s;
cout<<"Enter fileNames :";
while(cin>>filename && filename!="@")
files.push_back(filename);
ifstream input;
vector<string>::const_iterator it=files.begin();
while(it!=files.end())
{
input.open(it->c_str());
if(!input)
{
   cerr<<"error:can not open file:"
    <<*it<<endl;
   input.clear();
   ++it;
}
else
{
   while(input>>s)
    process(s);
   input.close();
   input.clear();
   ++it;
}
}
return 0;
}

void process(string s )
{cout<<s<<endl;}
这个例子是读取文件名,然后将文件的内容列出来。

有windows底下没有文件结束符(ctrl+z被行)所以想个办法用@作为结束符

下面是另一个例子:

#include<iostream>
#include<fstream>
#include<sstream>
#include<vector>
using namespace std;

int fileToVector(string fileName,vector<string> &svec)
{
ifstream inFile(fileName.c_str());
if(!inFile)
   return 1;
string s ;
while(getline(inFile,s))
   svec.push_back(s);
inFile.close();
if(inFile.bad())
   return 2;
if(inFile.eof())
   return 4;
if(inFile.fail())
   return 3;
}
int main()
{
vector<string>svec;
string fileName,s;
    cout<<"Enter filename:"<<endl;
cin>>fileName;
switch(fileToVector(fileName,svec))
{
case 1:
   cout<<"error:can not open file:"
    <<fileName<<endl;
   return -1;
case 2:
   cout<<"error:system failure"<<endl;
   return -1;
case 3:
   cout<<"error:read failure"<<endl;
   return -1;
}
string word;
istringstream isstream;
for(vector<string>::iterator iter=svec.begin();
   iter!=svec.end();++iter)
{
   isstream.str(*iter);
   while(isstream>>word)
    cout<<word<<endl;
   isstream.clear();
}
return 0;
}

字符串流

istringstream

ostringstream

stringstream

这个三个流就是处理字符串流的。

抱歉!评论已关闭.