首先看看流中各个类的继承情况:
看了图以后各个类的继承情况就了解清楚了。。。。
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
这个三个流就是处理字符串流的。