C++ Primer笔记8---chapter8 IO库
Posted Ston.V
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ Primer笔记8---chapter8 IO库相关的知识,希望对你有一定的参考价值。
1.标准库定义了三种类型的IO,其中包括iostream(istream/ostream),fstream(ifstream/ofstream),sstream(istringstream/ostringstream);其中ifstream和istringstream都继承自istream
另外为了支持使用宽字符的语言,也定义了一组类型来操纵wchat_t类型的数据。
2. IO对象无拷贝或者赋值,进行IO操作的函数通常以引用的方式传递和返回流。(之前就提到过有一些对象无法进行拷贝)
读写IO对象会改变其状态,因此传递和返回引用不能const的。
3. 条件状态:
常见的状态有strm::badbit(发生错误,无法恢复),strm::failbit(发生错误,可以修正,能继续使用),strm::eofbit(读到文件尾),strm::goodbit(当前流正常,此时此值为0)
同样也有s.clear() s.clear(flags) s.setstate(flags) s.rdstate()等相关接口
当读到文件尾时,s.eof() s.fail()都会返回true(其他的标志也有对应的类似函数来返回)
//复位failbit和badbig,保持其他标志位不变,以位操作的方式设置 cin.clear(cin.rdstate() & ~cin.failbit & ~cin.bafbit);
4. 管理流的输出缓冲:
缓冲区刷新的几种原因:程序正常结束,缓冲区满,使用操纵符如endl来刷新,使用操纵符unitbuf来设置流的状态以清空缓冲区(默认对ceer设置unitbuf,因此写到cerr的内容都是立刻刷新的),读写被关联的输出流导致与之关联的流也随之刷新
几种操纵符:endl,flush,ends,unifbuf
cout<< "hi" <<endl; //换行并刷新缓冲区 cout<< "hi" <<flush; //不附带任何字符的刷新缓冲区 cout<< "hi" <<end; //输出一个空字符并刷新和缓冲区 cout<<unitbuf; //所有的输出操作后都会进行一次flush来刷新缓冲区 cout<<nounitbuf; //回到正常的输出方式
当一个输入流被关联到一个输出流,任何对输入流读取数据的操作都会先刷新关联的输出流
。每个流最多同时关联到一个流,但多个流可以同时关联到同一个ostream
cin.tie(&cout); //关联cin和cout //old_tie指向当前cin关联的流(如果有的话) ostream *old_tie = cin.tie(nullptr); //cin不在与其他流关联 cin.tie(&cerr); //读取cin会刷新cerr而不是cout cin.tie(old_tie); //重建cin和cout间的正常关联
但是对于流关联的理解,我仍不清楚,刷新输出缓冲区似乎也并不是直接输出的意思,写了测试code也没有预期效果
cin.tie(&cout); int a=0; cin>>a; cout<<a<<endl; //我以为会输出两次,结果只输出一次 cin.tie(&cerr); cin>>a; //我以为会有一次输出,结果并没有 return 0;
5.文件输入输出:这个都比较熟悉,用的也很多,这里不再赘述,有别人的文章很不错
https://blog.csdn.net/hbqjzx/article/details/86525693
注意1:当使用out方式(写)打开文件时,默认就是trunc的,如果不想源文件内容被清空,就需要追加ofstream::app
注意2:一个流和文件已经绑定时就不能继续绑定其他文件了,我们可以使循环中自动的构造和析构多个流来操作多个文件
//这段code确实写的好,main函数接受一个需要处理的文件列表,这里处理的好 for(auto p=argv+1;p!=argv+argc;++p){ //第一个参数是函数名,所以要argv+1 ifstream input(*p); if(input){ process(input); }else{ cerr<<"couldn't open: "+ string(*p); }//每个循环input都会离开作用域因而被销毁 }
注意3:<< 和 >> 箭头往哪指就是数据往哪流,cin>>s就是数据从标准输入流到s中去
6.string流:
包括istringstream,ostringstream,stringstream
stringstream特有操作 sstream ss ss是一个未被绑定的stringstream对象。sstream是sstream中定义的一个类型 sstream ss(s) ss保存string s的一个拷贝,构造函数是explicit的 ss.str() 返回strm所保存的string的拷贝 ss.str(s) 将s拷贝到ss当中,返回void 一般的用途是:
1.方便的进行string串(中间有空格)之间的分割
这里书上的code写的好,直接copy上来
#include <string> #include <iostream> #include <sstream> using namespace std; /*现在如下记录格式,每个人名后面跟着多个电话号码 *可以使用stringstream方便的将其按照空格分割 * *morgan 20123123 413243241 *drew 41324214 *lee 414324 4231421 5453513 */ struct PersonInfo{ string name; vector<string>phones; }; int main(){ //进行输入,这里输入用流,便于分割 string line,word; //保存一行记录和分割开的单词 vector<PersonInfo>people; while(getline(cin,line)){ PersonInfo info; istringstream record(line); //读取一行数据,record是流对象 record >> info.name; //得到name while(record >> word) //得到phones info.phones.push_back(word); people.push_back(people); } //进行输出,这里用流输出,方便将多个string整合到一起 //假定已经有了vaild()和format()函数来验证电话号码和进行格式转换,最终只输出具有有效号码的信息 for(const auto &entry : people){ ostringstream formatted,badNums; for(const auto &nums : entry.phones){ if(!valid(nums)){ badNums << " " << nums; //将无效的号码写到badnums流中,以空格间隔 }else formatted << " " << format(nums); //将有效的号码改变格式后写入formatted流中去,以空格间隔 } if(badNums.str().empty()) //没有错误的数 os << entry.name << " " << formatted.str() <<endl; else //有错误的就打印出来 cerr << "input error: " << entry.name << "invlid number(s)" << badNums.str() << endl; } }
2.进行数据类型转换(使用sstream),如int转换为string(在C语言中使用sprintf或者itoa)
#include <string> #include <iostream> #include <sstream> #include <cstdlib> using namespace std; int main(){ stringstream ss; string s("123"); int res=0; ss<<s; ss>>res; cout<<res<<endl; //scanf(screen,format,data),sprintf(screen,format,data),实际上screen只是省略了 //在这里换成char *类型了,这样方便记忆转换顺序 string s1("234"); sscanf(s1.c_str(),"%d",&res); //需要stdio头文件 cout<<res<<endl; //数字转C字符串是使用sprintf函数 res=atoi("345"); //需要有cstdlib头文件 cout<<res<<endl; //数字转C字符串是使用itoa函数(integer to ascii) }
以上是关于C++ Primer笔记8---chapter8 IO库的主要内容,如果未能解决你的问题,请参考以下文章
C++ Primer笔记16---chapter13 代码实例
C++ Primer笔记16---chapter13 代码实例
C++ Primer笔记15---chapter13 拷贝控制2