目录前面已经在用的IO库设施IO类IO对象不能拷贝或赋值条件状态管理输出缓冲文件输入输出fstream特有的操作文件模式string流stringstream特有的操作练习练习1练习2练习3练习4练习5练习6练习7练习8练习9总结
前面已经在用的IO库设施 istream:输入流类型,提供输入操作。 ostream:输出流类型,提供输出操作 cin:一个istream对象,从标准输入读取数据。 cout:一个ostream对象,向标准输出写入数据。 cerr:一个ostream对象,向标准错误写入消息。 >>运算符:用来从一个istream对象中读取输入数据。 <<运算符:用来向一个ostream对象中写入输出数据。 getline函数:从一个给定的istream对象中读取一行数据,存入到一个给定的string对象中。
IO类 iostream
头文件:从标准流中读写数据,istream
,ostream
等 fstream
头文件:从文件中读写数据,ifstream
,ofstream
等 sstream
头文件:从字符串中读写数据,istringstream
,ostringstream
IO对象不能拷贝或赋值
由于不能拷贝IO对象,因此不能将 形参 或 返回类型 设置为 流类型。进行 IO 操作的函数通常以 引用方式 传递和 返回流。读写一个IO对象会改变其状态,因此 传递和返回的引用不能用const。
IO对象不能存在容器里. 形参和返回类型也不能是流类型。 形参和返回类型一般是流的引用。 读写一个IO对象会改变其状态,因此传递和返回的引用不能是const的。
条件状态
上表中,strm是一种IO类型,(如istream), s是一个流对象。
管理输出缓冲 每个输出流都管理一个缓冲区,用来保存程序读写的数据。文本串可能立即打印出来,也可能被操作系统保存在缓冲区内,随后再打印。 刷新(即,数据真正写到输出设备或文件)缓冲区的IO操纵符 endl
:输出一个换行符并刷新缓冲区 flush
:刷新流,但不添加任何字符 ends
:在缓冲区插入空字符null,然后刷新 unitbuf
:告诉流接下来每次操作之后都要进行一次flush操作。 nounitbuf
:回到正常的缓冲方式
文件输入输出
头文件fstream定义了三个类型来支持文件IO:
ifstream
从一个给定文件读取数据。 ofstream
向一个给定文件写入数据。 fstream
可以读写给定文件。
fstream特有的操作
上表中,fstream
是头文件fstream
中定义的一个类型,fstrm是一个文件流对象。
文件模式
string流
头文件sstream
定义了三个类型来支持内存IO:
istringstream
从string读取数据。 ostringstream
向string写入数据。 stringstream
可以读写给定string。
stringstream特有的操作
上表中sstream
是头文件sstream
中任意一个类型。s是一个string。
书中演示demo使用
#include <iostream>#include <string>#include <vector>#include <sstream>using namespace std;typedef struct PersonInfo{string name;vector<string> phones;}p;int main() {string line, word;vector<p> people;while (getline(cin, line)){p info;istringstream record(line);record >> info.name;while (record >> word)info.phones.push_back(word);people.push_back(info);}for (auto i : people){cout << i.name << endl;for (auto j : i.phones)cout << j << " ";cout << endl;}return 0;}
练习
练习1
编写函数,接受一个istream&参数,返回值类型也是istream&。此函数须从给定流中读取数据,直至遇到文件结束标识时停止。它将读取的数据打印在标准输出上。完成这些操作后,在返回流之前,对流进行复位,使其处于有效状态。
解:
std::istream& func(std::istream &is){ std::string buf; while (is >> buf) std::cout << buf << std::endl; is.clear(); return is;}
练习2
测试函数,调用参数为cin。
解:
#include <iostream>using std::istream;istream& func(istream &is){ std::string buf; while (is >> buf) std::cout << buf << std::endl; is.clear(); return is;}int main(){ istream& is = func(std::cin); std::cout << is.rdstate() << std::endl; return 0;}
测试
#include <iostream>#include <string>using namespace std;istream& f1(istream& is){int s;while (is >> s){cout << s << endl;}return is;}istream& f2(istream& is){int s;while (is >> s){cout << s << endl;}is.clear();return is;}int main(){istream& is = f1(cin);cout << is.rdstate() << endl;istream& is2 = f2(cin);cout << is2.rdstate() << endl;return 0;}
练习3
什么情况下,下面的while循环会终止?
while (cin >> i) /* ... */
如badbit、failbit、eofbit 的任一个被置位,那么检测流状态的条件会失败。
练习4
编写函数,以读模式打开一个文件,将其内容读入到一个string的vector中,将每一行作为一个独立的元素存于vector中。
#include <iostream>#include <string>#include <vector>#include <fstream>using namespace std;void ReadFileToVec(const string& filename, vector<string>& vec){ifstream ifs(filename);if (ifs){string buf;while (getline(ifs, buf))vec.push_back(buf);}}
练习5
重写上面的程序,将每个单词作为一个独立的元素进行存储。
void ReadFileToVec(const string& fileName, vector<string>& vec){ ifstream ifs(fileName); if (ifs) { string buf; while (ifs >> buf) vec.push_back(buf); }}
练习6
编写程序,将来自一个文件中的行保存在一个vector中。然后使用一个istringstream从vector读取数据元素,每次读取一个单词。
#include <iostream>#include <string>#include <sstream>#include <fstream>#include <vector>using namespace std;int main(){//将来自一个文件的行保存到vector中ifstream ifs("hello.txt");if (!ifs){cerr << "no data ?" << endl;return -1;}vector<string> vecline;string line;while(getline(ifs, line))vecline.push_back(line);ifs.close();//从vector读取元素,每次只读一个单词for (auto &s : vecline){istringstream iss(s);string word;while (iss >> word)cout << word << endl;}return 0;}
练习7
本节的程序在外层while循环中定义了istringstream对象。如果record对象定义在循环之外,你需要对程序进行怎样的修改?重写程序,将record的定义移到while循环之外,验证你设想的修改方法是否正确。
解:
#include <iostream>#include <sstream>#include <string>#include <vector>using std::vector; using std::string; using std::cin; using std::istringstream;struct PersonInfo { string name; vector<string> phones;};int main(){ string line, word; vector<PersonInfo> people; istringstream record; while (getline(cin, line)) { PersonInfo info; record.clear(); record.str(line); record >> info.name; while (record >> word) info.phones.push_back(word); people.push_back(info); } for (auto &p : people) { std::cout << p.name << " "; for (auto &s : p.phones) std::cout << s << " "; std::cout << std::endl; } return 0;}
练习8
我们为什么没有在PersonInfo中使用类内初始化?
解:
因为这里只需要聚合类就够了,所以没有必要在PersionInfo中使用类内初始化。
练习9
电话号码程序
#include <iostream>#include <string>#include <sstream>#include <fstream>#include <vector>using namespace std;struct PersonInfo {string name;vector<string> phones;};bool valid(const string& str){return isdigit(str[0]);}string format(const string& str){return str.substr(0, 3) + "-" + str.substr(3, 3) + "-" + str.substr(6);}int main(){//从文件中读取信息存入vector容器ifstream ifs("phone.txt");if (!ifs){cerr << "no phone numbers ? " << endl;return -1;}vector<PersonInfo> people;string line, word;istringstream record;while (getline(ifs, line)){PersonInfo info;record.clear();record.str(line);record >> info.name;while (record >> word){info.phones.push_back(word);}people.push_back(info);}//逐个验证电话号码 并 改变其格式for (const auto& entry : people) //对people中的每一项{//每个循环创建的对象ostringstream formatted, badnums;//对每个数for (const auto& nums : entry.phones){if (!valid(nums)){badnums << " " << nums;//将数的字符串形式存入badnums}else{//将格式化的字符串写入formattedformatted << " " << format(nums);}}//没有错误的数if (badnums.str().empty()){cout << entry.name << " "<< formatted.str() << endl;}else{//打印名字和错误的数cerr << "input error: " << entry.name<< " invalid number(s)" << badnums.str() << endl;}}return 0;}
总结
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注自由互联的更多内容!
当你见过了世界上最美丽的风景,