流是什么
流,简单来说就是建立在面向对象基础上的一种抽象的处理数据的工具。在流中,定义了一些处理数据的基本操作,如读取数据,写入数据等,程序员是对流进行所有操作的,而不用关心流的另一头数据的真正流向。流不但可以处理文件,还可以处理动态内存、网络数据等多种数据形式。如果你对流的操作非常熟练,在程序中利用流的方便性,写起程序会大大提高效率的。
——百科
流又是类。
各种流的关系
cin,cout 与 <<,>>
cin
cin,一个istream对象,从标准输入读取数据。
利用输入运算符>>,它接受一个istream作为其左侧运算对象,接受一个对象作为其右侧运算对象。它从给定的istream读入数据,并存入给定的对象。返回其左侧运算对象作为其计算结果。
cout
cout,一个ostream对象。向标准输出写入数据。
利用输出运算符<<,它接受一个ostream作为其左侧运算对象,接受一个对象作为其右侧运算对象。右侧的对象是将要打印的值,将给定的值写入ostream对象中。输出结果为左侧运算对象。
理解
从输入读取数据
向输出写入数据
理解这两句话,进行其他操作。
fstream
文件流是继承自iostream。与iostream、sstream共同作为头文件构成IO标准库。
使用fstream定义文件流,与文件相关联,可以进行文件操作
ifstream
写文件
1.声明流
2.使用流打开文件
3.使用>>运算符
4.关闭流
#include <iostream>
#include <fstream>
using namespace std;
int main () {
fstream mycout;
mycout.open("data.txt");
char p[100];
int i = 0;
while ( (p[i] = getchar()) != '#') {
mycout << p[i];
++i;
}
mycout.close();
}
ifstream只写,可用fstream替换。
ofstream
读文件
1.声明流
2.将流与文件绑定
3.使用<<运算符
4.关闭流
#include <iostream>
#include <fstream>
using namespace std;
int main () {
fstream file;
file.open("data.txt");
char p[100];
file >> p;
cout << p;
file.close();
}
ofstream只读,可用fstream替换。
其他
参数 | 功能 |
---|---|
ios::in | 读 |
ios::out | 写 |
ios::app | 从文件末尾开始写 |
ios::binary | 二进制模式 |
ios::trunc | 打开一个文件,然后清空内容 |
ios::ate | 打开一个文件时,将位置移动到文件尾 |
函数 | 功能 |
---|---|
good() | 如果文件打开成功 |
bad() | 打开文件时发生错误 |
eof() | 到达文件尾 |
stringstream
C++引入了ostringstream、istringstream、stringstream这三个类,要使用他们创建对象就必须包含sstream头文件。
istringstream类 用于执行C++风格的串流的输入操作。
ostringstream类 用于执行C风格的串流的输出操作。
strstream类 同时可以支持C风格的串流的输入输出操作。
istringstream
#include <iostream>
#include <sstream>
using namespace std;
int main() {
istringstream istr;
istr.str("1 3.14");
//等价于 istringstream istr("1 56.7");
cout << istr.str() << endl;
int a;
float b;
istr >> a;
cout << a << endl;
istr >> b;
cout << b << endl;
return 0;
}
从上述代码(从另外的博客采摘),我们可以看出, istreamstream创建一个流。
函数str(),返回流中的数据。数据间的空格将数据类型分明。
从方式上可以初始化流,也可以用str()函数给流赋予数据。
>> 读取流中数据,赋值给变量。
ostringstream
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main() {
ostringstream ostr;
ostr.str("abc");
//如果构造的时候设置了字符串参数,那么增长操作的时候不会从结尾开始增加,而是修改原有数据,超出的部分增长
string ch = ostr.str();
cout << ch << endl;
ostr.put('d');
ostr.put('e');
ostr << "fg";
string gstr = ostr.str();
cout << gstr;
}
如代码(其他博客采摘修改),put可以给流存储数据,也可以初始化,也可以从<<向流中写入数据。
stringstream
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main() {
stringstream ostr("ccc");
string ch = ostr.str();
cout << ch << endl;
ostr.put('d');
ostr.put('e');
ostr << "fg";
string gstr = ostr.str();
cout << gstr << endl;
char a;
ostr >> a;
cout << a;
}
从上代码,可知,我们可以初始化流,可以用put函数写入流,对象也可以通过>>读取流中的数据。
结合了istream与ostream的特点,通常使用stringstream。
流的处理
流有两种状态,一是正常流,二是错误流。当流的状态错误时,无法再向数据中输入流。
一些关于流的函数
函数 | 功能 |
---|---|
eof() | 若流的eofbit置位,则返回true; |
fail() | 若流的failbit或badbit置位,则返回true; |
bad() | 若流的badbit置位,则返回true; |
good() | 若流处于有效状态,则返回true; |
clear() | 将所有条件状态位复位,将流的状态设置为有效 |
rdstate() | 返回流的当前状态值 |
有关量
量 | 使用 |
---|---|
failbit | 用来指出一个IO操作失败了; |
eofbit | 用来指出流到达了结尾; |
badbit | 用来指出流已经崩溃; |
goodbit | 用来表示流正确; |
如何改变
当发生系统级错误时,如不可恢复的错误,badbit被置位,即流无法被使用。
当发生可恢复错误时,failbit被置位,如读取错误;
当达到文件结尾时,eofbit和failbit都会被置位;
badbit,faibit,eofbit,任何一个被置位,流的状态条件为失败即假。
函数的使用
操作一:清除错误流并重新输入值
#include <iostream>
using namespace std;
int main () {
int num = 0;
int a = 0;
cin >> num;
cin.clear();
cin.ignore();
cin >> a;
cout << num << ' ' << a << endl;
}
在上述代码中,当输入num时不为数字,流状态变为错误。使用cin.clear()将其错误流状态清除,但此时无法再向流中输入数据,ignore(),默认忽略流中字符,但默认为一个,使其可以再向流中输入数据,从而执行cin>>a;语句。
#include <iostream>
using namespace std;
int main () {
int num;
int a = 0;
cin >> num;
cin.clear();
cin.sync();
cin >> a;
cout << num << ' ' << a << endl;
}
而使用sync()与ignore()不同,sync()将缓冲区内容写回磁盘,所以错误流中后的所以字符都将被写入,而不只是ignore一个字符。清除了错误流。使用回车可继续执行cin>>a;
using namespace std;
int main()
{
stringstream ss;
int i = 0;
for(i = 0; i < 5; i++ )
{
ss << "hello";
string s = ss.str();
cout << s.size() << endl;
// 如下两部可彻底恢复ss
ss.clear(); // 恢复状态
ss.str(""); // 恢复值
}
}
恢复stringstream的值。
操作二:fail()函数的使用
#include <iostream>
#include <sstream>
using namespace std;
int main () {
string s;
stringstream ss;
int n, i, sum, a;
cin >> n;
getline(cin, s);
for (i=0; i<n; i++) {
getline(cin, s);
ss.clear();
ss.str(s);
sum=0;
while (1) {
ss >> a;
if ( ss.fail() ) break;
sum+=a;
}
cout << sum << endl;
}
}
该代码将一行的数字相加。当流到达末尾时,fail()函数为真。
转:另外,由于程序并不总是知道外部输入的进度,很难控制是不是全部清除输入缓冲区的内容。通常我们有可能只是希望放弃输入缓冲区中的一部分,而不是全部。比如清除掉当前行、或者清除掉行尾的换行符等等。但要是缓冲区中已经有了下一行的内容,这部分可能是我们想保留的。这个时候最好不要用sync()。可以考虑用ignore函数代替。
cin.ignore(numeric_limits::max(),’\n’);//清除当前行
cin.ignore(numeric_limits::max()); //清除cin里所有内容
不要被长长的名字吓倒,numeric_limits::max()不过是climits头文件定义的流使用的最大值,你也可以用一个足够大的整数代替它。
使用ignore显然能比sync()更精确控制缓冲区。
还有ignore()这样用,可以清除一个字符。不过这个用的不多,对于清楚知道要弃置一个字符的情况,完全可以由程序做一次读操作,然后放弃读入内容来实现。
最后
博客内容参考了http://blog.youkuaiyun.com/joeblackzqq/article/details/7032703;
有兴趣的,可以参考该博客。