C++ Primer 学习笔记_26_标准I/O库(续) --文件的输入与输出、字符串流

来源:互联网 发布:淘宝开放平台api 权限 编辑:程序博客网 时间:2024/04/29 09:09


标准I/O

--文件的输入与输出、字符串流

一、文件的输入与输出

    fstream头文件定义了三种支持文件IO的类型:ifstream,ofstream,fstream。这些类型都由相应的iostream类型派生而来,这样就意味着我们已经了解fstream的大部分内容了。特别是,可以使用IO操作符(<<>>)在文件上实现格式化IO

    fstream类型还定义了两个自己的新操作–openclose,以及形参为要打开的文件名的构造函数。


1、需要读写文件时,则必须定义自己的对象,并将他们绑定在需要的文件上:

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. //定义并打开一对fstream对象  
  2.     string ifile = "/home/xiaofang/c++primer/code/c++14/input";  
  3.     string ofile = "/home/xiaofang/c++primer/code/c++14/output";  
  4.   
  5.     ifstream infile(ifile.c_str());  
  6.     ofstream outfile(ofile.c_str());  
  7.   
  8.     string str;  
  9.   
  10.     while (infile >> str)  
  11.         outfile << str << '\t';  

ifstreamofstream对象提供文件名作为初始化式,就相当于打开了特定的文件。


[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. ifstream infile;  
  2. ofstream outfile;  

定义infile为读文件流对象,定义outfile为写文件流对象。这两个流对象都没有捆绑具体的文件,在使用fstream对象之前,还必须使这些对象捆绑特定的要读写的文件:

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. infile.open(ifile.c_str());  
  2. outfile.open(ofile.c_str());  

调用open成员函数将已存在的fstream对象与特定文件绑定。


2、检查文件打开是否成功

    打开文件之后,通常需要检验文件打开是否成功,这是一个好习惯!

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. if (!infile)  
  2. {  
  3.     cerr << "Error: unable to open input file: "  
  4.          << ifile << endl;  
  5.     return -1;  
  6. }  

3、将文件流对象与新文件重新绑定

    如果要把fstream对象与另一个不同的文件关联,则必须先关闭(close)现在的文件,然后打开(open)另一个文件:

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. ifstream infile("in");  
  2. infile.close();  
  3. infile.open("next");  

open函数会检查流是否已经打开,如果已经打开,则设置内部状态,以指出发生了错误。接下来使用流的任何尝试都会失败。


4、清除文件流状态

    如果文件结束符或者其他错误,将设置流的内部状态,以便以后不允许再对该流做读写操作。而关闭流并不能改变流对象的内部状态。如果最后的读写操作失败了,则对象的状态将保持为错误模式,知道执行clear操作重新恢复流的状态为止。调用clear之后,就像重新创建了该对象一样。

    如果打算重用已存在的流对象,那么while循环必须在每次循环时记得关闭(close)和清空(clear)文件流

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. ifstream input;  
  2. vector<string>::const_iterator it = files.begin();  
  3.   
  4. while (it != files.end())  
  5. {  
  6.     input.open(it -> c_str());  
  7.   
  8.     if (!input)  
  9.         break;  
  10.   
  11.     while (input >> s)  
  12.         process(s);  
  13.   
  14.     input.close();  
  15.     input.clear();  
  16.     ++it;  
  17. }  

    如果忽略clear调用,则循环只能读入第一文件。如果在关闭该流前没有调用clear清除流状态,接着在input上做的任何输入运算都会失败。

【小心地雷o(∩∩)o...

    如果需要重用文件流读写多个文件,必须在读另一个文件之前调用clear清除该流的状态。

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. //P254 习题8.6  
  2. std::istream &get(std::istream &in)  
  3. {  
  4.     string ival;  
  5.     while (in >> ival,!in.eof())  
  6.     {  
  7.         if (in.bad())  
  8.         {  
  9.             throw runtime_error("IO stream corrupted");  
  10.         }  
  11.         else if (in.fail())  
  12.         {  
  13.             std::cerr << "bad data,try again";  
  14.             in.clear();  
  15.             in.ignore(200,' ');  
  16.             continue;  
  17.         }  
  18.         std::cout << ival << '\t';  
  19.     }  
  20.     std::cout << endl;  
  21.   
  22.     return in;  
  23. }  
  24.   
  25. int main()  
  26. {  
  27.     ifstream infile("/home/xiaofang/c++primer/code/c++14/input");  
  28.     get(infile);  
  29. }  

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. //习题8.7  
  2.     ifstream input;  
  3.     string str;  
  4.     vector<string>::const_iterator iter = files.begin();  
  5.     while (iter != files.end())  
  6.     {  
  7.         input.open(iter -> c_str());  
  8.         if (!input)  
  9.         {  
  10.             cerr << "Open error,again!" << endl;  
  11.             ++ iter;  
  12.             continue;  
  13.         }  
  14.         while (input >> str)  
  15.         {  
  16.             cout << str << endl;  
  17.         }  
  18.         ++ iter;  
  19.         input.close();  
  20.         input.clear();  
  21.     }  

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. //习题8.8  
  2.     string str;  
  3.     vector<string>::const_iterator it = files.begin();  
  4.     while (it != files.end())  
  5.     {  
  6.         ifstream infile(it -> c_str());  
  7.         if (!infile)  
  8.         {  
  9.             cerr << "Open error,again!";  
  10.         }  
  11.         else  
  12.         {  
  13.             while (infile >> str)  
  14.                 cout << str << '\t';  
  15.         }  
  16.         cout << endl;  
  17.         ++it;  
  18.     }  

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. //习题8.9  
  2. int fileLineToVector(const string &path,vector<string> &strVec)  
  3. {  
  4.     ifstream in(path.c_str());  
  5.     string line;  
  6.     while (getline(in,line))  
  7.     {  
  8.         strVec.push_back(line);  
  9.     }  
  10.     in.close();  
  11.     if (in.eof())  
  12.         return 2;  
  13.     if (in.fail())  
  14.         return 4;  
  15.     if (in.bad())  
  16.         return 1;  
  17.     return 0;  
  18. }  
  19. int main()  
  20. {  
  21.     string path("/home/xiaofang/c++primer/code/c++14/input");  
  22.   
  23.     vector<string> strVec;  
  24.     fileLineToVector(path,strVec);  
  25.   
  26.     for (vector<string>::const_iterator iter = strVec.begin();iter != strVec.end(); ++iter)  
  27.     {  
  28.         cout << *iter << endl;  
  29.     }  
  30. }  

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. //8.10  
  2. int fileWordToVector(const string &path,vector<string> &strVec)  
  3. {  
  4.     ifstream in(path.c_str());  
  5.     string word;  
  6.     while (in >> word)  
  7.     {  
  8.         strVec.push_back(word);  
  9.     }  
  10.     in.close();  
  11.     if (in.eof())  
  12.         return 2;  
  13.     if (in.fail())  
  14.         return 4;  
  15.     if (in.bad())  
  16.         return 1;  
  17.     return 0;  
  18. }  

5、文件模式

    每个fstream类都定义了一组表示不同模式的值,用于指定流打开的不同模式。可用位操作符设置一个或多个模式。

in

打开文件做读操作

out

打开文件做写操作

app

在每次写之前找到文件尾

ate

打开文件后立即将文件定位在文件尾

trunc

打开文件时清空已存在的文件流

binary

以二进制模式进行 IO操作

 outtruncapp模式只能用于指定ofstreamfstream对象的关联工作;in模式只能用于指定ifstreamfstream对象的关联工作;所有的文件都可以用atebinary模式打开,ate模式只在打开时有效!ate模式只在打开时有效:文件打开后将定位在文件结尾。以binary模式打开的流则将文件以字节序列的形式处理,而不解释流中的字符。

    默认时,ifstream流对象关联的文件将以in模式打开,该模式允许文件做读的操作:ofstream关联的文件则以out模式打开,使文件可写。以out模式打开的文件会被清空:丢弃该文件存储的所有数据。

    从效果来看,ofstream对象指定out模式等效于同时指定了outtrunc模式。

    对于ofstream打开的文件,要保存文件中已存在的数据,唯一方法是显示的指定app模式打开:

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. ofstream outfile("file1");  
  2. //与上一条语句作用相同  
  3. ofstream outfile("file1",ofstream::out | ofstream::trunc);  
  4. ofstream outfile_app("file2",ofstream::app);  

6、对同一个文件做输入和输出运算

    默认情况下,fstream对象以inout模式同时打开。当文件同时以inout打开时不清空,而如果打开fstream所关联的文件时,只使用out模式,而不指定in模式,则文件会被清空。如果以trunc模式打开,则无论是否指定in模式,文件同样会被清空。

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. fstream InOut("file");  
  2. //作用相同  
  3. fstream InOut("file",fstream::in | fstream::out);  

7、模式是文件的属性而不是流的属性

    每次打开文件都会设置模式:

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. ofstream outFile;  
  2. outFile.open("scratchpad",ofstream::out);  
  3. outFile.close();  
  4. outFile.open("precious",ofstream::app);  
  5. outFile.close();  
  6. outFile.open("out");  

只要调用 open函数,就要设置文件模式,其模式的设置可以是显式的也可以是隐式的。如果没有指定文件模式,将使用默认值。


8、打开模式的有效组合

out

打开文件做写操作,删除文件中已有的数据

out | trunc

out模式相同

out | app

打开文件做写操作,在文件尾写入

in

打开文件做读操作

in | out

打开文件做读、写操作,并定位于文件开头处

in | out | trunc

打开文件做读、写操作,删除文件中已有的数据

上述所有打开模式组合还可以添加ate模式,对这些模式添加ate只会改变文件打开时的初始定位,在第一次读或写之前,将文件定位于文件末尾处。


9、一个示例程序

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. ifstream &open_file(ifstream &in,const string &str)  
  2. {  
  3.     in.close();  
  4.     in.clear();  
  5.     in.open(str.c_str(),ifstream::in);  
  6.     return in;  
  7. }  

由于不确定流in的状态,因此首先调用closeclear将这个流设置为有效状。最后返回的in要么已经与指定文件绑定,要么处于错误状态。

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. //P256 习题8.13  
  2. ofstream &open_file_out(ofstream &out,const string &str)  
  3. {  
  4.     out.close();  
  5.     out.clear();  
  6.     out.open(str.c_str(),ofstream::out | ofstream::app);  
  7.     return out;  
  8. }  

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. //习题8.14  
  2. ifstream &open_file_in(ifstream &in,const string &str)  
  3. {  
  4.     in.close();  
  5.     in.clear();  
  6.     in.open(str.c_str(),ifstream::in);  
  7.     return in;  
  8. }  
  9. ofstream &open_file_out(ofstream &out,const string &str)  
  10. {  
  11.     out.close();  
  12.     out.clear();  
  13.     out.open(str.c_str(),ofstream::out | ofstream::app);  
  14.     return out;  
  15. }  
  16.   
  17. int main()  
  18. {  
  19.     ifstream in;  
  20.     ofstream out;  
  21.     open_file_in(in,"/home/xiaofang/c++primer/code/c++14/input");  
  22.     open_file_out(out,"/home/xiaofang/c++primer/code/c++14/output");  
  23.     string str;  
  24.     while (in >> str)  
  25.     {  
  26.         out << str << endl;  
  27.     }  
  28. }  

二、字符串流

    sstream所定义的类用于读写存储在内存中的string对象。

标准库定义了三种类型的字符串流:

    istringstream,istream派生而来,提供读string的功能。

    ostringstream,ostream派生而来,提供写string的功能。

    stringstream,iostream派生而来,提供读写string功能。

要使用上述类,必须包含sstream头文件。

    与fstream类型一样,上述类型由iostream类型派生而来,这意味着iostream上所有的操作适用于sstream中的类型sstream类型除了继承的操作外,还各自定义了一个string形参的构造函数,这个构造函数将string类型的实参复制给    stringstream对象stringstream的读写操作实际上读对写的就是该对象中的string对象。这些类还定义了名为str的成员,用来读取或设置stringstream对象所操纵的string

stringstream strm;

创建自由的 stringstream对象

stringstream strm(s);

创建存储 s的副本的stringstream对象,sstring类型的对象

strm.str();

返回 strm中存储的string类型对象

strm.str(s);

string类型的s复制给strm,返回void


1stringstream对象的使用

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. string line,word;  
  2. while (getline(cin,line))  
  3. {  
  4.     istringstream stream(line);  
  5.   
  6.     while (stream >> word)  
  7.     {  
  8.         // do per-word ...  
  9.     }  
  10. }  

将一个istringstream对象与所读取的行绑定起来,这样只需使用普通的string输入操作符即可读出每行中的单词。


2stringstream提供的转换和/或格式化

    stringstream对象的一个常见用法是,需要在多种数据类型之间实现自动格式化时使用该类类型。或反之。sstream输入和输出操作可自动地把算术类型转化为相应的string表示形式,反过来也可以。

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. // 一个数值型数据集合, 要获取它们的 string 表 示形式  
  2.     ostringstream format_massage;  
  3.     int val1 = 512,val2 = 1024;  
  4.     format_massage << "val1: " << val1 << '\n'  
  5.                    << "val2: " << val2 << endl;  
  6.     cout << format_massage.str() << endl;  

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. //反过来  
  2.     istringstream input_istring(format_massage.str());  
  3.     int val3,val4;  
  4.     string tmp;  
  5.     input_istring >> tmp >> val3 >> tmp >> val4;  
  6.     cout << val3 << endl;  
  7.     cout << val4 << endl;  

    为了读取input_string,必须把该string对象分解为若干部分。为了得到它们,必须读取(忽略)处于所需数据周围的标号。

    一般情况下,使用输入操作符读string时,空白符将会忽略,于是,在读与format_message关联的string时,忽略其中的换行符。

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. //综合  
  2.     stringstream massage;  
  3.     int val1 = 512,val2 = 1024;  
  4.     massage << "val1: " << val1 << '\n'  
  5.             << "val2: " << val2 << endl;  
  6.     cout << massage.str() << endl;  
  7.   
  8.     int val3,val4;  
  9.     string tmp;  
  10.     massage >> tmp >> val3 >> tmp >> val4;  
  11.     cout << val3 << endl;  
  12.     cout << val4 << endl;  

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. //P258 习题8.15  
  2. istream &get(istream &in)  
  3. {  
  4.     string str;  
  5.     while (in >> str,!in.eof())  
  6.     {  
  7.         if (in.bad())  
  8.         {  
  9.             throw runtime_error("IO stream corrupted");  
  10.         }  
  11.         else if (in.fail())  
  12.         {  
  13.             cerr << "bad data,try again" << endl;  
  14.             in.clear();  
  15.             in.ignore(200,' ');  
  16.             continue;  
  17.         }  
  18.         cout << str << '\t';  
  19.     }  
  20.     cout << endl;  
  21.     return in;  
  22. }  
  23. int main()  
  24. {  
  25. //  freopen("input","r",stdin);  
  26.     string line;  
  27.     getline(cin,line);  
  28.     line += ' ';  
  29.     stringstream isstr(line);  
  30.     get(isstr);  
  31. }  

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. //习题8.16  
  2. int main()  
  3. {  
  4.     ifstream infile("/home/xiaofang/c++primer/code/c++14/input");  
  5.     vector<string> lineVec;  
  6.     string line,word;  
  7.   
  8.     while (getline(infile,line))  
  9.     {  
  10.         lineVec.push_back(line);  
  11.     }  
  12.   
  13.     for (vector<string>::const_iterator iter = lineVec.begin(); iter != lineVec.end(); ++iter)  
  14.     {  
  15.         istringstream isstream(*iter);  
  16.         while (isstream >> word)  
  17.         {  
  18.             cout << word << '\t';  
  19.         }  
  20.         cout << endl;  
  21.     }  
  22.   
  23.     stringstream isstream;  
  24.     for (vector<string>::const_iterator iter = lineVec.begin(); iter != lineVec.end(); ++iter)  
  25.     {  
  26.        isstream.str(*iter);  
  27.        while (isstream >> word)  
  28.        {  
  29.             cout << word << endl;  
  30.        }  
  31.        isstream.clear();  
  32.     }  
  33. }  

0 0
原创粉丝点击