第八章 IO库
练习8.1
编写函数,接受一个istream&
参数,返回值类型也是istream&
。此函数须从给定流中读取数据,直至遇到文件结束标识时停止。它将读取的数据打印在标准输出上。完成这些操作后,在返回流之前,对流进行复位,使其处于有效状态。
解:
1 2 3 4 5 6 7 8 std::istream& func (std::istream &is) { std::string buf; while (is >> buf) std::cout << buf << std::endl; is.clear (); return is; }
练习8.2
测试函数,调用参数为cin
。
解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #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 ; }
练习8.3
什么情况下,下面的while
循环会终止?
解:
如badbit
、failbit
、eofbit
的任一个被置位,那么检测流状态的条件会失败。
练习8.4
编写函数,以读模式打开一个文件,将其内容读入到一个string
的vector
中,将每一行作为一个独立的元素存于vector
中。
解:
1 2 3 4 5 6 7 8 9 10 void ReadFileToVec (const string& fileName, vector<string>& vec) { ifstream ifs (fileName) ; if (ifs) { string buf; while (getline (ifs, buf)) vec.push_back (buf); } }
练习8.5
重写上面的程序,将每个单词作为一个独立的元素进行存储。解:
1 2 3 4 5 6 7 8 9 10 void ReadFileToVec (const string& fileName, vector<string>& vec) { ifstream ifs (fileName) ; if (ifs) { string buf; while (ifs >> buf) vec.push_back (buf); } }
练习8.6
重写7.1.1节的书店程序,从一个文件中读取交易记录。将文件名作为一个参数传递给main
。
解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include <fstream> #include <iostream> #include "../ch07/ex7_26.h" using std::ifstream; using std::cout; using std::endl; using std::cerr;int main (int argc, char **argv) { ifstream input (argv[1 ]) ; Sales_data total; if (read (input, total)) { Sales_data trans; while (read (input, trans)) { if (total.isbn () == trans.isbn ()) total.combine (trans); else { print (cout, total) << endl; total = trans; } } print (cout, total) << endl; } else { cerr << "No data?!" << endl; } return 0 ; }
练习8.7
修改上一节的书店程序,将结果保存到一个文件中。将输出文件名作为第二个参数传递给main
函数。
解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include <fstream> #include <iostream> #include "../ch07/ex7_26.h" using std::ifstream; using std::ofstream; using std::endl; using std::cerr;int main (int argc, char **argv) { ifstream input (argv[1 ]) ; ofstream output (argv[2 ]) ; Sales_data total; if (read (input, total)) { Sales_data trans; while (read (input, trans)) { if (total.isbn () == trans.isbn ()) total.combine (trans); else { print (output, total) << endl; total = trans; } } print (output, total) << endl; } else { cerr << "No data?!" << endl; } return 0 ; }
练习8.8
修改上一题的程序,将结果追加到给定的文件末尾。对同一个输出文件,运行程序至少两次,检验数据是否得以保留。
解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include <fstream> #include <iostream> #include "../ch07/ex7_26.h" using std::ifstream; using std::ofstream; using std::endl; using std::cerr;int main (int argc, char **argv) { ifstream input (argv[1 ]) ; ofstream output (argv[2 ], ofstream::app) ; Sales_data total; if (read (input, total)) { Sales_data trans; while (read (input, trans)) { if (total.isbn () == trans.isbn ()) total.combine (trans); else { print (output, total) << endl; total = trans; } } print (output, total) << endl; } else { cerr << "No data?!" << endl; } return 0 ; }
练习8.9
使用你为8.1.2节第一个练习所编写的函数打印一个istringstream
对象的内容。
解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <iostream> #include <sstream> using std::istream;istream& func (istream &is) { std::string buf; while (is >> buf) std::cout << buf << std::endl; is.clear (); return is; } int main () { std::istringstream iss ("hello" ) ; func (iss); return 0 ; }
练习8.10
编写程序,将来自一个文件中的行保存在一个vector
中。然后使用一个istringstream
从vector
读取数据元素,每次读取一个单词。
解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #include <iostream> #include <fstream> #include <sstream> #include <vector> #include <string> using std::vector; using std::string; using std::ifstream; using std::istringstream; using std::cout; using std::endl; using std::cerr;int main () { ifstream ifs ("../data/book.txt" ) ; if (!ifs) { cerr << "No data?" << endl; return -1 ; } vector<string> vecLine; string line; while (getline (ifs, line)) vecLine.push_back (line); for (auto &s : vecLine) { istringstream iss (s) ; string word; while (iss >> word) cout << word << endl; } return 0 ; }
练习8.11
本节的程序在外层while
循环中定义了istringstream
对象。如果record
对象定义在循环之外,你需要对程序进行怎样的修改?重写程序,将record
的定义移到while
循环之外,验证你设想的修改方法是否正确。
解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 #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.12
我们为什么没有在PersonInfo
中使用类内初始化?
解:
因为这里只需要聚合类就够了,所以没有必要在PersionInfo
中使用类内初始化。
练习8.13
重写本节的电话号码程序,从一个命名文件而非cin
读取数据。
解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 #include <iostream> #include <sstream> #include <fstream> #include <string> #include <vector> using std::vector; using std::string; using std::cin; using std::istringstream;using std::ostringstream; using std::ifstream; using std::cerr; using std::cout; using std::endl;using std::isdigit;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 () { ifstream ifs ("../data/phonenumbers.txt" ) ; if (!ifs) { cerr << "no phone numbers?" << endl; return -1 ; } string line, word; vector<PersonInfo> people; 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) { ostringstream formatted, badNums; for (const auto &nums : entry.phones) if (!valid (nums)) badNums << " " << nums; else formatted << " " << 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 ; }
练习8.14
我们为什么将entry
和nums
定义为const auto&
?
解:
它们都是类类型,因此使用引用避免拷贝。在循环当中不会改变它们的值,因此用const
。