> 文章列表 > 《C++ Primer Plus》第17章:输入、输出和文件(7)

《C++ Primer Plus》第17章:输入、输出和文件(7)

《C++ Primer Plus》第17章:输入、输出和文件(7)

编程练习

  1. 编写一个程序计算输入流中第一个$之前的字符数目,并将$留在输入流中。

    #include<iostream>int main() {int ct = 0;while(std::cin.peek()!='$'){ct++;std::cin.get();}std::cout << "num: " << ct << std::endl;return 0;
    }
    

    答:

    #include<iostream>int main() {int ct = 0;while(std::cin.peek()!='$'){ct++;std::cin.get();}std::cout << "num: " << ct << std::endl;return 0;
    }
    
  2. 编写一个程序,将键盘输入(直到模拟的文件尾)复制到通过命令行指定的文件中。

    #include <cstdlib>
    #include <iostream>
    #include <fstream>
    #include <string>int main(int argc, char *argv[]){if(argc<2){std::cout << "Usage: " << argv[0] << " <filename>" << std::endl;exit(EXIT_FAILURE);}std::fstream fs;for(int file = 1; file < argc; file++){fs.open(argv[file], std::ios_base::out);if(!fs.is_open()){std::cerr << "error happens when open " << argv[file] << ".\\n";exit(EXIT_FAILURE);}std::cout << "Please enter your input: \\n";std::string input;getline(std::cin, input);while(input.size()>0){fs << input << std::endl;getline(std::cin, input);}fs.clear();fs.close();fs.open(argv[file], std::ios_base::in); if(!fs.is_open()){std::cerr << "error happens when open " << argv[file] << ".\\n";exit(EXIT_FAILURE);}std::cout << "The content of the " << argv[file] << ":\\n";char ch;while(fs.get(ch)){std::cout << ch;}if(!fs.eof()){std::cerr << "error happens when read " << argv[file] << ".\\n";exit(EXIT_FAILURE);}return 0;}
    }
    

    答:

    #include <cstdlib>
    #include <iostream>
    #include <fstream>
    #include <string>int main(int argc, char *argv[]){if(argc<2){std::cout << "Usage: " << argv[0] << " <filename>" << std::endl;exit(EXIT_FAILURE);}std::fstream fs;for(int file = 1; file < argc; file++){fs.open(argv[file], std::ios_base::out);if(!fs.is_open()){std::cerr << "error happens when open " << argv[file] << ".\\n";exit(EXIT_FAILURE);}std::cout << "Please enter your input: \\n";std::string input;getline(std::cin, input);while(input.size()>0){fs << input << std::endl;getline(std::cin, input);}fs.clear();fs.close();fs.open(argv[file], std::ios_base::in); if(!fs.is_open()){std::cerr << "error happens when open " << argv[file] << ".\\n";exit(EXIT_FAILURE);}std::cout << "The content of the " << argv[file] << ":\\n";char ch;while(fs.get(ch)){std::cout << ch;}if(!fs.eof()){std::cerr << "error happens when read " << argv[file] << ".\\n";exit(EXIT_FAILURE);}return 0;}
    }
    
  3. 编写一个程序,将一个文件复制到另一个文件中。让程序通过命令行获取文件名。如果文件无法打开,程序将指出这一点。

    //#include <cstdlib>
    #include<fstream>
    #include<iostream>
    #include<string>int main(int argc, char* argv[]){if(argc!=3){std::cout << "Usage: "  << argv[0] << " <target filename>  <sourse filename>.\\n";exit(EXIT_FAILURE);}std::ofstream ofs;ofs.open(argv[1], std::ios_base::out);if(!ofs.is_open()){std::cerr << "Error happen when open " << argv[1] << ".\\n";exit(EXIT_FAILURE);}std::ifstream ifs;ifs.open(argv[2], std::ios_base::in);if(!ifs.is_open()){std::cerr << "Error happen when open " << argv[2] << ".\\n";exit(EXIT_FAILURE);}std::string line;getline(ifs,line);while(line.size()>0){ofs << line << std::endl;getline(ifs,line);}if(!ifs.eof()){std::cerr << "Error happens when read " << argv[1] << ".\\n";}return 0;
    }
    

    答:

    //#include <cstdlib>
    #include<fstream>
    #include<iostream>
    #include<string>int main(int argc, char* argv[]){if(argc!=3){std::cout << "Usage: "  << argv[0] << " <target filename>  <sourse filename>.\\n";exit(EXIT_FAILURE);}std::ofstream ofs;ofs.open(argv[1], std::ios_base::out);if(!ofs.is_open()){std::cerr << "Error happen when open " << argv[1] << ".\\n";exit(EXIT_FAILURE);}std::ifstream ifs;ifs.open(argv[2], std::ios_base::in);if(!ifs.is_open()){std::cerr << "Error happen when open " << argv[2] << ".\\n";exit(EXIT_FAILURE);}std::string line;getline(ifs,line);while(line.size()>0){ofs << line << std::endl;getline(ifs,line);}if(!ifs.eof()){std::cerr << "Error happens when read " << argv[1] << ".\\n";}return 0;
    }
    
  4. 编写一个程序,它打开两个文本文件进行输入,打开一个文本文件进行输出。该程序将两个输入文件中对应的行并接起来,并用空格分隔,然后将结果写入到输出文件中。如果一个文件比另一个短,则将较长文件中余下的几行值复制到输出文件中。例如,假设第一个输入文件的内容如下:

    eggs kites donuts
    balloons hammers
    stones
    

    而第二个输入文件的内容如下:

    zero lassitude
    finance drama
    

    则得到的文件的内容将如下:

    eggs kites donuts zero lassitude
    balloons hammers finance drama
    stones
    

    答:

    #include <cstdlib>
    #include<iostream>
    #include<fstream>
    #include<string>using namespace std;int main(int argc, char* argv[]) {if(argc!=4){cerr << "Usage: " << argv[0] << " <source file1> <source file2> <target file>.\\n";exit(EXIT_FAILURE);}ifstream ifs1(argv[1], ios_base::in);ifstream ifs2(argv[2], ios_base::in);ofstream ofs(argv[3], ios_base::out);if(!ifs1.is_open()) {cerr << "Error when open " << argv[1] << ".\\n";}if(!ifs2.is_open()) {cerr << "Error when open " << argv[2] << ".\\n";}string line1, line2;getline(ifs1, line1);getline(ifs2,line2);while(line1.size() >0 && line2.size() >0 ){ofs << line1 << ' ' << line2 << endl;getline(ifs1, line1);getline(ifs2,line2);}if(!ifs1.eof()){while(line1.size()>0){ofs << line1 << endl;getline(ifs1, line1);}}if(!ifs2.eof()){while(line2.size()>0){ofs << line2 << endl;getline(ifs2, line2);}}return 0;
    }
    
  5. Mat 和 Pat 想邀请他们的朋友来参加派对,就像第16章中的编程练习8那样,但现在他们希望程序使用文件。他们请您编写一个完成下述任务的程序。

    • 从文本文件 mat.dat 中读取 Mat 朋友的清单,其中每行为一个朋友。姓名将被存储在容器,然后按顺序显示出来。
    • 从文本文件 pat.dat 中读取 Pat 朋友的姓名清单,其中每行为一个朋友。姓名将被存储在容器,然后按顺序显示出来。
    • 合并两个清单,删除重复的条目,并将结果保存在文件 matnpat.dat 中,其中每行为一个朋友。

    答:

    #include <cstdlib>
    #include<iostream>
    #include<fstream>
    #include<string>
    #include<vector>
    #include<set>int main() {using namespace std;ifstream matin("mat.dat", ios_base::in);ifstream patin("pat.dat", ios_base::in);if(!(matin && patin)){cerr << "Failed to open input files.\\n";exit(EXIT_FAILURE);}ofstream matnpatout("matnpat.dat", ios_base::out);if(!matnpatout.is_open()){cerr << "Failed to open output files.\\n";exit(EXIT_FAILURE);}vector<string> mat;vector<string> pat;string name;while(!matin.eof()) {       getline(matin, name);mat.push_back(name);}cout << "Success" << endl;while(!patin.eof()) {getline(patin, name);pat.push_back(name);}cout << "Mat's friends:\\n";for(auto& name : mat){cout << name << endl;}cout << "Pat's friends:\\n";for(auto& name : pat) {cout << name << endl;}set<string> matnpat;matnpat.insert(mat.begin(), mat.end());matnpat.insert(pat.begin(), pat.end());for(auto& name : matnpat) {matnpatout << name << endl;}return 0;
    }
    
  6. 编写一个程序,它使用标准 C++ I/O、文件 I/O 以及 14 章的编程练习5中定义的 employee、manager、fink 和 highfink 类型的数据。该程序应包含程序17.7中的代码行,即允许用户将新数据添加到文件中。该程序首次被运行时,将要求用户输入数据,然后显示所有数据,并将这些信息保存到一个文件中。当该程序再次被运行时,将首先读取并显示文件中的数据,然后让用户添加数据,并显示所有的数据。差别之一是,应通过一个指向 employee 类型的指针来处理数据。这样,指针可以指向 employee 对象,也可以指向从 employee 派生出来的其他三种对象中的任何一种。使数组较小有助于检查程序,例如,您可能将数组限定为最多包含 10 个元素:

    const int MAX = 10;		// no more than 10 objects
    ...
    employee * pc [MAX];
    

    为通过键盘输入,程序应使用一个菜单,让用户选择要创建的对象类型。菜单将使用一个 switch,以便使用 new 来创建指定类型的对象,并将它的地址赋给 pc 数组中的一个指针。然后该对象可以使用虚函数 setall() 来提示用户输入相应的数据:

    pc[i] -> setall();		// invokes function corresponding to type of object
    

    为将数据保存到文件中,应设计一个虚函数 writeall():

    for (i = 0; i < index; i++) {pc[i] -> writeall(fout);		// fout ofstream connected to output file
    }
    

    注意:对于这个练习,应使用文本 I/O,而不是二进制 I/O(遗憾的是,虚对象包含指向虚函数指针表的指针,而 write() 将把这种信息复制到文件中。使用 read() 读取文件的内容,以填充对象时,函数指针将为乱码,这将扰乱虚函数的行为)。可使用换行符将字段分隔开,这样在输入时将很容易识别各个字段。也可以使用二进制 I/O,但不能将对象作为一个整体写入,而应该提供分别对每个类成员应用 write() 和 read() 的类方法。这样,程序将只把所需的数据保存到文件中。

    比较难处理的部分是使用文件恢复数据。问题在于:程序如何才能直到接下来要恢复的项目是 employee 对象、manager 对象、fink 对象还是 highfink 对象?一种方法是,在对象的数据写入文件时,在数据前面加上一个指示对象类型的数据。这样,在文件输入时,程序便可以读取该整数,并使用 switch 语句创建一个适当的对象来接收数据:

    enum classkind{Employee, Manager, Fink, Highfink};		// in class header
    ...
    int classtype;
    while((fin>>classtype).get(ch) ) { // newline separates int from dataswitch(classtype) {case Employee  	: pc[i] = new employee;: break;
    

    然后便可以使用指针调用虚函数 getall() 来读取信息:

    pc[i++] -> getall();
    

    答:
    emp.h

    #ifndef EMP_H_
    #define EMP_H_#include<iostream>
    #include<fstream>
    #include<string>enum classkind {Employee, Manager, Fink, Highfink}; // in class headerclass ab_emp {;
    private:std::string fname;std::string lname;std::string job;
    public:ab_emp();ab_emp(const std::string & fn, const std::string & ln,const std::string & j);virtual void ShowAll() const;virtual void SetAll();virtual std::ofstream & WriteAll(std::ofstream & of) const;friend std::ostream & operator<<(std::ostream & os, const ab_emp & e);virtual ~ab_emp() = 0;
    };class employee : virtual public ab_emp {
    public:employee();employee(const std::string & fn, const std::string & ln,const std::string & j);virtual void ShowAll() const;virtual void SetAll();std::ofstream & WriteAll(std::ofstream & of) const;
    };class manager : virtual public ab_emp {
    private:int inchargeof;
    protected:int InChargeOf() const {return inchargeof;}int & InChargeOf() {return inchargeof;}
    public:manager();manager(const std::string & fn, const std::string & ln,const std::string & j, int ico = 0);manager(const ab_emp & e, int ico);manager(const manager & m);virtual void ShowAll() const;virtual void SetAll();std::ofstream & WriteAll(std::ofstream & of) const;
    };class fink : virtual public ab_emp {
    private:std::string reportsto;
    protected:std::string ReportsTo() const { return reportsto;}std::string & ReportsTo() {return reportsto;}
    public:fink();fink(const std::string & fn, const std::string ln,const std::string & j, const std::string repo);fink(const ab_emp & e, const std::string repo);fink(const fink & f);virtual void ShowAll() const;virtual void SetAll();std::ofstream & WriteAll(std::ofstream & of) const; 
    };class highfink : public manager, public fink {
    public:highfink();highfink(const std::string & fn, const std::string & ln,const std::string & j, const std::string & rpo,int ico);highfink(const ab_emp & e, const std::string & rpo, int ico);highfink(const fink & f, int ico);highfink(const manager & m, const std::string & rpo);highfink(const highfink & h);virtual void ShowAll() const;virtual void SetAll();std::ofstream & WriteAll(std::ofstream & fout) const;
    };#endif
    

    emp.cpp

    #include"17-6_emp.h"
    #include <fstream>
    #include <ostream>
    #include <string>// ab_emp methods
    ab_emp::ab_emp() {fname = "none";lname = "none";job = "none";
    }ab_emp::ab_emp(const std::string & fn, const std::string & ln,const std::string & j) : fname(fn), lname(ln), job(j)
    {
    }ab_emp::~ab_emp() {}void ab_emp::ShowAll() const {std::cout << "firstname: " << fname << std::endl;std::cout << "lastname: " << lname << std::endl;std::cout << "job: " << job << std::endl;
    }void ab_emp::SetAll() {std::cout << "Enter firstname: ";std::getline(std::cin, fname);std::cout << "Enter lastname: ";std::getline(std::cin, lname);std::cout << "Enter job: ";std::getline(std::cin, job);
    }std::ofstream & ab_emp::WriteAll (std::ofstream &of) const{of << fname << " " << lname << " " << job;return of;
    }std::ostream & operator<<(std::ostream & os, const ab_emp & e){os << e.fname << " " << e.lname << " " << e.job;return os;
    }// employee methods
    employee::employee(){}employee::employee(const std::string & fn, const std::string & ln,const std::string & j): ab_emp(fn, ln, j)
    {}void employee::ShowAll() const {ab_emp::ShowAll();
    }void employee::SetAll() {ab_emp::SetAll();
    }std::ofstream & employee::WriteAll(std::ofstream &of) const {of << Employee << " ";ab_emp::WriteAll(of);return of;
    }// manager methods
    manager::manager() {inchargeof = 0;
    }manager::manager(const std::string & fn, const std::string & ln,const std::string & job, int ico): ab_emp(fn, ln, job), inchargeof(ico)
    {
    }manager::manager(const ab_emp & e, int ico) : ab_emp(e), inchargeof(ico) {}manager::manager(const manager & m) : ab_emp(m), inchargeof(m.inchargeof){}void manager::ShowAll() const {ab_emp::ShowAll();std::cout << "InchargeOf: " << inchargeof << std::endl;
    }void manager::SetAll() {ab_emp::SetAll();std::cout << "Enter inchargeof: ";std::cin >> inchargeof;std::cin.get();
    }std::ofstream & manager::WriteAll(std::ofstream &of) const {of << Manager << " ";ab_emp::WriteAll(of) << " " << inchargeof;return of;
    }// fink methods
    fink::fink() {reportsto = "none";
    }fink::fink(const std::string & fn, const std::string ln,const std::string & job, const std::string repo) : ab_emp(fn,ln,job), reportsto(repo)
    {}fink::fink(const ab_emp & e, const std::string repo): ab_emp(e), reportsto(repo)
    {}fink::fink(const fink & f): ab_emp(f) ,reportsto(f.reportsto)
    {
    }void fink::ShowAll() const
    {ab_emp::ShowAll();std::cout << "Reportsto: " << reportsto << std::endl;
    }void fink::SetAll()
    {ab_emp::SetAll();std::cout << "Enter reportsto: ";std::getline(std::cin, reportsto);
    }std::ofstream & fink::WriteAll(std::ofstream & fout) const
    {fout << Fink << " ";ab_emp::WriteAll(fout)<< " " << reportsto;return fout;
    }// highfink methods
    highfink::highfink(){}highfink::highfink(const std::string & fn, const std::string & ln,const std::string & j, const std::string & repo, int ico): ab_emp(fn,ln,j), manager(fn,ln,j,ico), fink(fn,ln,j, repo)
    {}highfink::highfink(const ab_emp & e, const std::string & repo, int ico): ab_emp(e), manager(e,ico), fink(e,repo)
    {}highfink::highfink(const fink & f, int ico): ab_emp(f), fink(f), manager((const ab_emp &)f, ico)
    {}highfink::highfink(const manager & m, const std::string & repo): ab_emp(m), manager(m), fink((const ab_emp &)m, repo)
    {}highfink::highfink(const highfink & h): ab_emp(h), manager(h), fink(h)
    {}void highfink::ShowAll() const {ab_emp::ShowAll();std::cout << "ReportsTo: " << fink::ReportsTo() << std::endl;std::cout << "Inchargeof: "<< manager::InChargeOf() << std::endl;
    }void highfink::SetAll() {ab_emp::SetAll();std::cout << "Enter reportsto: ";std::getline(std::cin, fink::ReportsTo());std::cout << "Enter inchargeof: ";std::cin>>manager::InChargeOf();std::cin.get();
    }std::ofstream & highfink::WriteAll(std::ofstream &fout) const {fout << Highfink << " ";ab_emp::WriteAll(fout) << " " << fink::ReportsTo() << " " << manager::InChargeOf();return fout;
    }
    

    main.cpp

    #include"17-6_emp.h"
    #include <fstream>using namespace std;inline void showline(int n);
    void show_menu();
    inline void eatline();const int MAX = 10;int main() {ab_emp* pc[MAX];int ct; // number counterstring fname, lname, job, reportsto;int inchargeof;// read from fileifstream fin("out.txt", ios_base::in);if(fin.is_open()){int kind;while(fin>>kind){switch (kind) {case Employee:fin >> fname;fin >> lname;fin >> job;pc[ct] = new employee(fname, lname, job);break;case Manager:fin >> fname;fin >> lname;fin >> job;fin >> inchargeof;pc[ct] = new manager(fname, lname, job, inchargeof);break;case Fink:fin >> fname;fin >> lname;fin >> job;fin >> reportsto;pc[ct] = new fink(fname, lname, job, reportsto);break;case Highfink:fin >> fname;fin >> lname;fin >> job;fin >> reportsto;fin >> inchargeof;pc[ct] = new highfink(fname, lname, job, reportsto, inchargeof);break;}ct++;}cout << "content in out.txt: " << endl;for(int i=0; i<ct; i++){pc[i]->ShowAll();}fin.close();}// add elementschar choice;show_menu();while(cin>>choice && choice!='q' && ct<MAX){eatline();switch (choice) {case 'e':pc[ct] = new employee;pc[ct]->SetAll();break;case 'm':pc[ct] = new manager;pc[ct]->SetAll();break;case 'f':pc[ct] = new fink;pc[ct]->SetAll();break;case 'h':pc[ct] = new highfink;pc[ct]->SetAll();break;}ct++;show_menu();}for(int i=0 ; i<ct; i++){pc[i]->ShowAll();}// write to fileofstream fout("out.txt", ios_base::out);for(int i=0; i<ct; i++){pc[i]->WriteAll(fout);fout << endl;}fout.close();cout << "all contents written to out.txt\\n";for(int i=0; i<ct;i++){delete pc[i];}return 0;}void show_menu(){ios_base::fmtflags old_fmt = cout.setf(ios_base::left, ios_base::adjustfield);showline(35);cout.width(20);cout << "e. employee";cout << "m. manager" << endl;cout.width(20);cout << "f. fink";cout << "h. highfink" << endl;cout << "q. quit" << endl;showline(35);cout << "Select a type: " << endl;cout.setf(old_fmt);
    }inline void showline(int n){cout.fill('-');cout.width(n);cout << "-" << endl;cout.fill(' ');
    }inline void eatline() {while(cin.get() != '\\n') continue;
    }
    
  7. 下面是某个程序的部分代码。该程序将键盘输入读取到一个由 string 对象组成的 vector 中,将字符串内容(而不是 string 对象)存储到一个文件中,然后该文件的内容复制到另一个由 string 对象组成的 vector 中。

    int main() {using namespace std;vector<string> vostr;string temp;// acquire stringscout << "Enter strings (empty line to quit) : \\n";while (getline(cin, temp) && temp[0] != '\\0' ) {vostr.push_back(temp);}cout << "Here is your intput.\\n ";for_each(vostr.begin(), vostr.end(), ShowStr);// store in a fileofstream fout("strings.dat", ios_base::out | ios_base::binary);for_each(vostr.begin(), vostr.end(), Store(fout));fout.close;// recover file contentsvector<string> vistr;ifstream fin("strings.dat", ios_base::in | ios_base::binary);if (!fin.is_open() ) {cerr << "Could not open file for input.\\n";exit(EXIT_FAILURE);}GetStrs(fin, vistr);cout << "\\nHere are the strings read from the file:\\n";for_each(vistr.begin(), vistr.end(), ShowStr);return 0;
    }
    

    该程序以二进制格式打开文件,并想使用 read() 和 write() 来完成 I/O。余下的工作如下所述。

    • 编写函数 void ShowStr(const string &),它显示一个 string 对象,并在显示完后换行。
    • 编写函数符 Store,它将字符串信息写入到文件中。Store 的构造函数应接受一个指定 ifstream 对象的参数,而重载的 operator()(const string &) 应指出要写入到文件中的字符串。一种可行的计划是,首先将字符串的长度写入到文件中,然后将字符串的内容写入到文件中。例如,如果 len 存储了字符串的长度,可以这样做:
      os.write((char *) &len, sizeof(std::size_t));		// store length
      os.write(s.data(), len);
      

      成员函数 data() 返回一个指针,该指针指向一个其中存储了字符串中字符的数组。它类似于成员函数 c_str(),只是后者在数组末尾加上了一个空字符。

    • 编写函数 GetStrs(),它根据文件恢复信息。该函数可以使用 read() 来获得字符串的长度,然后使用一个循环从文件中读取相应数量的字符,并将它们附加到一个原来为空的临时 string 末尾。由于 string 的数据是私有的,因此必须使用 string 类的方法来将数据存储到 string 对象中,而不能直接存储。

    答:

    #include <cstddef>
    #include <cstdlib>
    #include <ios>
    #include<iostream>
    #include<fstream>
    #include <ostream>
    #include<vector>
    #include<string>
    #include<algorithm>using namespace std;class Store {
    private:ostream &os;
    public:Store(ostream &o):os(o){}void operator()(const string & s){size_t len = s.length();os.write((const char *)&len, sizeof(std::size_t));os.write(s.data(),len);}
    };inline void ShowStr(const std::string& s) {cout << s << endl;
    }void GetStrs(std::ifstream & fin, std::vector<std::string> & vistr);int main(){using namespace std;vector<string> vostr;string temp;// acquire stringscout << "Enter strings (empty line to quit):\\n";while(getline(cin, temp)&&temp.size()>0){vostr.push_back(temp);}for_each(vostr.begin(), vostr.end(), ShowStr);// store in a fileofstream fout("string.dat", ios_base::out|ios_base::binary);for_each(vostr.begin(), vostr.end(), Store(fout));fout.close();cin.get();// recover file contentsvector<string> vistr;ifstream fin("string.dat", ios_base::in|ios_base::binary);if (!fin.is_open()){cerr << "Could not open file for input.\\n";exit(EXIT_FAILURE);}GetStrs(fin, vistr);cout << "\\nHere are the strings read from the file:\\n";for_each(vistr.begin(), vistr.end(),ShowStr);return 0;}void GetStrs(std::ifstream & fin, std::vector<std::string> & vistr){size_t len;     // string lengthwhile(fin.read( (char*)&len, sizeof(size_t) ) ){string str;char ch;for(int i=0; i< len; i++){fin.read(&ch,sizeof(char));str.push_back(ch);}vistr.push_back(str);}
    }