IO就是input和output和起来的缩写,在C++语言当中读写文件,控制台操作或者是磁盘以及内存读写都可以通过C++当中IO库来实现。网络上有许多关于io库的介绍,本文主要记录自己在实验当中情况、查阅资料的理解,以及对其他之前的高人博客内容的总结,参考资料是C++ primer第5版。
书中首先介绍了3个头文件,分别是
w字母开头的是为了支持使用宽字符的语言,wcin、wcout、wcerr分别对应cin、cout、cerr。
还没有用过宽字符型,自己敲了两下。宽字符型用cin和cout果然不好使,呵呵
#include
using namespace std;
int main()
{
ios::sync_with_stdio(false);
wchar_t c;
wcin>>c;
wcout<return 0;
}
###IO类型之间的关系
C++的标准库可以忽略掉不同类型在流操作这件的差异,这是用过继承实现的。例如,ifstream和istringstream都继承自istream。类似的继承如下,图片来自http://en.cppreference.com/w/cpp/io
因为继承关系的性质,可以把一个派生类对象当做基类对象使用,那么就可以使用ifstream和istringstream像使用cin一样去使用上面的这些对象。
比如经常会用到读取文件,写入文件的操作,以及把int转换成string的操作。
#include
using namespace std;
fstream in;
int main()
{
ios::sync_with_stdio(false);
int a;
in.open("data.txt");//里面放了一个整数
in>>a;//像cin一样去使用
cout<//输出读出的数据
in.close();//关闭文件流
return 0;
}
下面的代码是字符串转换成整数,然后加上1
#include
using namespace std;
int main()
{
ios::sync_with_stdio(false);
stringstream ss;
string s;
int a;
cin>>s;
ss<//stringstream可以像cin一样去使用,得益于继承的机制
ss>>a;
cout<1<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<;
cout<<istream::badbit<;
cout<<istream::eofbit<;
cout<<istream::failbit<;
}
如果代码里面仅仅输出状态,得到的结果是0,1,2,4。分别为iostate对应二进制的状态,这些状态可以用”|”运算符来组合使用。
000
001
010
100
找一个字符串流测试一下,代码来自cpp官网
#include
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()=0
failbit: good()=0 eof()=0 fail()=1 bad()=0
badbit: good()=0 eof()=0 fail()=1 bad()=1
这里先拿cin写一个测试的例子,书上举例说给一个整数读入字符串会出现错误,那会出现什么错误呢?
#include
using namespace std;
int main ()
{
int val;
cout<<cin.rdstate()<//最初的cin的状态
cout<<cin.good()<<cin.eof()<<cin.fail()<<cin.bad()<//输出cin各项状态值
cin>>val;//输入一个123试试
cout<<cin.good()<<cin.eof()<<cin.fail()<<cin.bad()<cin.clear();//清空,重置cin的状态为iostream::good
cin>>val;//输入qwe
cout<<cin.good()<<cin.eof()<<cin.fail()<<cin.bad()<return 0;
}
首先输出
0
1000
输入123后
1000
输入qwe后
0010
现在增加一个重新置位
#include
using namespace std;
int main ()
{
int val;
cout<<cin.rdstate()<//最初的cin的状态
cout<<cin.good()<<cin.eof()<<cin.fail()<<cin.bad()<//输出cin各项状态值
cin>>val;//输入一个123试试
cout<<cin.good()<<cin.eof()<<cin.fail()<<cin.bad()<cin.clear();//清空,重置cin的状态为iostream::good
cin>>val;//输入qwe
cout<<cin.good()<<cin.eof()<<cin.fail()<<cin.bad()<// cin.clear();//清空重置后结果
cin.clear(std::iostream::goodbit);//效果同上
cout<<cin.good()<<cin.eof()<<cin.fail()<<cin.bad()<return 0;
}
清空后输出结果就是1000了,因为cin被重新置位成了good
现在贴一个检查文件是否存在的,如果文件存在读入一个整数。如果文件不存在,输出错误,如果读到文件尾部,输出end of file!
#include
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<else
cerr<<"end of file!"<
首先先判断打开的文件是否存在,如果不存在则输出error opening!
while(!is.eof())的应用,如果is读取到文件尾部会设置eofbit状态,但是不会返回0,而是继续读取,所以如果读到了结尾还会在输出一次最后一行。这里用判断is.good()的方式来判断流是否正确。
刷新缓冲区
缓冲区就是把输入输出的放到内存当中,使用时再从内存当中取出。这样做的目的可以让cpu和硬件设施比如打印机之类的东西协调。
导致缓冲刷新的原因:
如何刷新?
#include
using namespace std;
int main ()
{
cout<<"hi"<cout<<"hi"<cout<<"hi"<cout<//全刷新
return 0;
}
如何关联输入输出?使用tie函数,它返回指向输出流的指针。
#include
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~