IO与流的处理

本文介绍了C++中的流,包括cin、cout、fstream、istringstream、ostringstream和stringstream的使用,以及流的状态管理和错误处理。重点讲解了如何进行输入输出操作,如何处理流的错误状态,并提供了相关函数的应用示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

流是什么

流,简单来说就是建立在面向对象基础上的一种抽象的处理数据的工具。在流中,定义了一些处理数据的基本操作,如读取数据,写入数据等,程序员是对流进行所有操作的,而不用关心流的另一头数据的真正流向。流不但可以处理文件,还可以处理动态内存、网络数据等多种数据形式。如果你对流的操作非常熟练,在程序中利用流的方便性,写起程序会大大提高效率的。
——百科
流又是类。
各种流的关系
这里写图片描述

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++引入了ostringstreamistringstreamstringstream这三个类,要使用他们创建对象就必须包含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函数写入流,对象也可以通过>>读取流中的数据。
结合了istreamostream的特点,通常使用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
有兴趣的,可以参考该博客。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值