C++ IO库

来源:互联网 发布:怎么查域名是否备案 编辑:程序博客网 时间:2024/05/29 04:27

IO就是input和output和起来的缩写,在C++语言当中读写文件,控制台操作或者是磁盘以及内存读写都可以通过C++当中IO库来实现。网络上有许多关于io库的介绍,本文主要记录自己在实验当中情况、查阅资料的理解,以及对其他之前的高人博客内容的总结,参考资料是C++ primer第5版。

IO类

书中首先介绍了3个头文件,分别是

  • < iostream > 定义了读写流的基本类型
    • —->istream 从流当中读取数据
    • —->wistream 宽字符版本,从流当中读取数据
    • —->ostream 向流当中写入数据
    • —->wostream 宽字符版本,向流当中写入数据
    • —->iostream 读写流
    • —->wiostream 宽字符读写流
  • < fstream >定义了读写命名文件的类型
    • —->ifstream,wifstream 从文件读取数据
    • —->ostream,wofstream 向文件写入数据
    • —->fstream,wfstream 读写文件
  • < sstream >
    • —->istringstream,wistringstream 从string读取数据
    • —->ostringstream, wostringstream 向string写入数据
    • —->stringstream,wstringstream 读写string

w字母开头的是为了支持使用宽字符的语言,wcin、wcout、wcerr分别对应cin、cout、cerr。

还没有用过宽字符型,自己敲了两下。宽字符型用cin和cout果然不好使,呵呵

#include <bits/stdc++.h>using namespace std;int main(){    ios::sync_with_stdio(false);    wchar_t c;    wcin>>c;    wcout<<c<<endl;    return 0;}

###IO类型之间的关系
C++的标准库可以忽略掉不同类型在流操作这件的差异,这是用过继承实现的。例如,ifstream和istringstream都继承自istream。类似的继承如下,图片来自http://en.cppreference.com/w/cpp/io
这里写图片描述
因为继承关系的性质,可以把一个派生类对象当做基类对象使用,那么就可以使用ifstream和istringstream像使用cin一样去使用上面的这些对象。
比如经常会用到读取文件,写入文件的操作,以及把int转换成string的操作。

#include <bits/stdc++.h>using namespace std;fstream in;int main(){    ios::sync_with_stdio(false);    int a;    in.open("data.txt");//里面放了一个整数    in>>a;//像cin一样去使用    cout<<a<<endl;//输出读出的数据    in.close();//关闭文件流    return 0;}

下面的代码是字符串转换成整数,然后加上1

#include <bits/stdc++.h>using namespace std;int main(){    ios::sync_with_stdio(false);    stringstream ss;    string s;    int a;    cin>>s;    ss<<s;//stringstream可以像cin一样去使用,得益于继承的机制    ss>>a;    cout<<a+1<<endl;    return 0;}

###IO对象没有拷贝或赋值
不能够将形参或返回类型设置为流类型,进行io操作的函数通常以引用的方式传递和返回流,读写io对象会改变其状态,因此传递和返回的引用不能是const的。
书上代码

ofstream out1,out2;out1=out2;//错误,不能赋值ofstream print(ofstream);//错误,不能初始化out2=print(out2);//错误,不能拷贝

IO的条件状态

IO的条件状态 strm::iostate iostate是一种极其相关的类型,提供了表达条件状态的完整功能 strm::badbit strm::iostate 类型的值,用于指流已经崩溃 strm::failbit strm::iostate 类型的值,用于指出失败的 IO 操作 strm::eofbit strm::iostate 类型的值,用于指出流已经到达文件结束 s.eof() 如果设置了流s的eofbit 值,则该函数返回 true s.fail() 如果设置了流s的failbit或badbit值,则该函数返回 true s.bad() 如果设置了流s的badbit值,则该函数返回 true s.good() 如果流 s 处于有效状态,则该函数返回 true s.clear() 将流s中所有条件状态复位,将流的状态设置为有效。返回void s.clear(flags) 根给定的flags标志位,将流s中对应条件状态位复位。flags的类型为iostate。返回void s.setstate(flags) 根据flags标志位,将流s中对应条件状态位职位。flags的类型为iostate。返回void s.rdstate() 返回流 s 的当前条件,返回值类型为 strm::iostate

其中iostate有四个值,分别是failbit, eofbit, badbit和goodbit
iostate拥有这四种状态,这四种状态是iostate的一个具体值。
通过代码输出结果

void state(){    cout<<istream::goodbit<<endl;    cout<<istream::badbit<<endl;    cout<<istream::eofbit<<endl;    cout<<istream::failbit<<endl;}

如果代码里面仅仅输出状态,得到的结果是0,1,2,4。分别为iostate对应二进制的状态,这些状态可以用”|”运算符来组合使用。
000
001
010
100

找一个字符串流测试一下,代码来自cpp官网

#include <bits/stdc++.h>using namespace std;void print_state (const std::ios& stream) {    std::cout << " good()=" << stream.good();        std::cout << " eof()=" << stream.eof();        std::cout << " fail()=" << stream.fail();        std::cout << " bad()=" << stream.bad();   }int main () {    std::stringstream stream;    stream.clear (stream.goodbit);        std::cout << "goodbit:"; print_state(stream); std::cout << '\n';    stream.clear (stream.eofbit);    std::cout << " eofbit:"; print_state(stream); std::cout << '\n';    stream.clear (stream.failbit);    std::cout << "failbit:"; print_state(stream); std::cout << '\n';    stream.clear (stream.badbit);    std::cout << " badbit:"; print_state(stream); std::cout << '\n';    return 0;}

结果可以运行一下看看,输出如下

goodbit: good()=1 eof()=0 fail()=0 bad()=0 eofbit: good()=0 eof()=1 fail()=0 bad()=0failbit: good()=0 eof()=0 fail()=1 bad()=0 badbit: good()=0 eof()=0 fail()=1 bad()=1

这里先拿cin写一个测试的例子,书上举例说给一个整数读入字符串会出现错误,那会出现什么错误呢?

#include <bits/stdc++.h>using namespace std;int main (){    int val;    cout<<cin.rdstate()<<endl;//最初的cin的状态    cout<<cin.good()<<cin.eof()<<cin.fail()<<cin.bad()<<endl; //输出cin各项状态值    cin>>val;//输入一个123试试    cout<<cin.good()<<cin.eof()<<cin.fail()<<cin.bad()<<endl;    cin.clear();//清空,重置cin的状态为iostream::good    cin>>val;//输入qwe    cout<<cin.good()<<cin.eof()<<cin.fail()<<cin.bad()<<endl;    return 0;}

首先输出
0
1000
输入123后
1000
输入qwe后
0010

现在增加一个重新置位

#include <bits/stdc++.h>using namespace std;int main (){    int val;    cout<<cin.rdstate()<<endl;//最初的cin的状态    cout<<cin.good()<<cin.eof()<<cin.fail()<<cin.bad()<<endl; //输出cin各项状态值    cin>>val;//输入一个123试试    cout<<cin.good()<<cin.eof()<<cin.fail()<<cin.bad()<<endl;    cin.clear();//清空,重置cin的状态为iostream::good    cin>>val;//输入qwe    cout<<cin.good()<<cin.eof()<<cin.fail()<<cin.bad()<<endl;//  cin.clear();//清空重置后结果    cin.clear(std::iostream::goodbit);//效果同上    cout<<cin.good()<<cin.eof()<<cin.fail()<<cin.bad()<<endl;    return 0;}

清空后输出结果就是1000了,因为cin被重新置位成了good

现在贴一个检查文件是否存在的,如果文件存在读入一个整数。如果文件不存在,输出错误,如果读到文件尾部,输出end of file!

#include <bits/stdc++.h>using namespace std;int main (){    ifstream is;    int a;    is.open ("data.txt");    if ( (is.rdstate() & ifstream::failbit ) != 0 )      {        cerr << "Error opening !"; return 0;    }    else    {        while(!is.eof())        {            is>>a;            if(is.good())                cout<<a<<endl;            else                cerr<<"end of file!"<<endl;        }    }    is.close();}

首先先判断打开的文件是否存在,如果不存在则输出error opening!
while(!is.eof())的应用,如果is读取到文件尾部会设置eofbit状态,但是不会返回0,而是继续读取,所以如果读到了结尾还会在输出一次最后一行。这里用判断is.good()的方式来判断流是否正确。

刷新缓冲区
缓冲区就是把输入输出的放到内存当中,使用时再从内存当中取出。这样做的目的可以让cpu和硬件设施比如打印机之类的东西协调。

导致缓冲刷新的原因:

  • 程序正常结束
  • 缓冲区满了
  • 使用endl(经常当换行使用了 呵呵)
  • 使用unitbuf
  • 一个输出流被关联到另一个流

如何刷新?

  1. endl操作符,用于输出一个换行符并刷新缓冲区
  2. flush操作符,用于刷新流,但不在输出中添加任何字符
  3. ends操作符,在缓冲区中插入空字符null,然后刷新
  4. 刷新所有输出,unitbuf操作
  5. 关联输入输出流
#include <bits/stdc++.h>using namespace std;int main (){    cout<<"hi"<<endl;    cout<<"hi"<<flush;    cout<<"hi"<<ends;    cout<<unitbuf;//全刷新    return 0;}

如何关联输入输出?使用tie函数,它返回指向输出流的指针。

#include <bits/stdc++.h>using namespace std;int main(){    ofstream out("data.txt");//放这个文件里面写东西    cin.tie(&out);//把cin关联到out上面    out<<123;//写入文件    int val;//    cin>>val;//只要使用cin,就会刷新输出流,这样123就被写进data.txt    return 0;}

to be continue~

0 0