C++ Primer 学习笔记_26_标准I/O库(续) --文件的输入与输出、字符串流
来源:互联网 发布:淘宝开放平台api 权限 编辑:程序博客网 时间:2024/04/29 09:09
标准I/O库
--文件的输入与输出、字符串流
一、文件的输入与输出
fstream头文件定义了三种支持文件IO的类型:ifstream,ofstream,fstream。这些类型都由相应的iostream类型派生而来,这样就意味着我们已经了解fstream的大部分内容了。特别是,可以使用IO操作符(<<和>>)在文件上实现格式化IO。
fstream类型还定义了两个自己的新操作–open和close,以及形参为要打开的文件名的构造函数。
1、需要读写文件时,则必须定义自己的对象,并将他们绑定在需要的文件上:
- //定义并打开一对fstream对象
- string ifile = "/home/xiaofang/c++primer/code/c++14/input";
- string ofile = "/home/xiaofang/c++primer/code/c++14/output";
- ifstream infile(ifile.c_str());
- ofstream outfile(ofile.c_str());
- string str;
- while (infile >> str)
- outfile << str << '\t';
为ifstream或ofstream对象提供文件名作为初始化式,就相当于打开了特定的文件。
- ifstream infile;
- ofstream outfile;
定义infile为读文件流对象,定义outfile为写文件流对象。这两个流对象都没有捆绑具体的文件,在使用fstream对象之前,还必须使这些对象捆绑特定的要读写的文件:
- infile.open(ifile.c_str());
- outfile.open(ofile.c_str());
调用open成员函数将已存在的fstream对象与特定文件绑定。
2、检查文件打开是否成功
打开文件之后,通常需要检验文件打开是否成功,这是一个好习惯!
- if (!infile)
- {
- cerr << "Error: unable to open input file: "
- << ifile << endl;
- return -1;
- }
3、将文件流对象与新文件重新绑定
如果要把fstream对象与另一个不同的文件关联,则必须先关闭(close)现在的文件,然后打开(open)另一个文件:
- ifstream infile("in");
- infile.close();
- infile.open("next");
open函数会检查流是否已经打开,如果已经打开,则设置内部状态,以指出发生了错误。接下来使用流的任何尝试都会失败。
4、清除文件流状态
如果文件结束符或者其他错误,将设置流的内部状态,以便以后不允许再对该流做读写操作。而关闭流并不能改变流对象的内部状态。如果最后的读写操作失败了,则对象的状态将保持为错误模式,知道执行clear操作重新恢复流的状态为止。调用clear之后,就像重新创建了该对象一样。
如果打算重用已存在的流对象,那么while循环必须在每次循环时记得关闭(close)和清空(clear)文件流:
- ifstream input;
- vector<string>::const_iterator it = files.begin();
- while (it != files.end())
- {
- input.open(it -> c_str());
- if (!input)
- break;
- while (input >> s)
- process(s);
- input.close();
- input.clear();
- ++it;
- }
如果忽略clear调用,则循环只能读入第一文件。如果在关闭该流前没有调用clear清除流状态,接着在input上做的任何输入运算都会失败。
【小心地雷o(∩∩)o...】
如果需要重用文件流读写多个文件,必须在读另一个文件之前调用clear清除该流的状态。
- //P254 习题8.6
- std::istream &get(std::istream &in)
- {
- string ival;
- while (in >> ival,!in.eof())
- {
- if (in.bad())
- {
- throw runtime_error("IO stream corrupted");
- }
- else if (in.fail())
- {
- std::cerr << "bad data,try again";
- in.clear();
- in.ignore(200,' ');
- continue;
- }
- std::cout << ival << '\t';
- }
- std::cout << endl;
- return in;
- }
- int main()
- {
- ifstream infile("/home/xiaofang/c++primer/code/c++14/input");
- get(infile);
- }
- //习题8.7
- ifstream input;
- string str;
- vector<string>::const_iterator iter = files.begin();
- while (iter != files.end())
- {
- input.open(iter -> c_str());
- if (!input)
- {
- cerr << "Open error,again!" << endl;
- ++ iter;
- continue;
- }
- while (input >> str)
- {
- cout << str << endl;
- }
- ++ iter;
- input.close();
- input.clear();
- }
- //习题8.8
- string str;
- vector<string>::const_iterator it = files.begin();
- while (it != files.end())
- {
- ifstream infile(it -> c_str());
- if (!infile)
- {
- cerr << "Open error,again!";
- }
- else
- {
- while (infile >> str)
- cout << str << '\t';
- }
- cout << endl;
- ++it;
- }
- //习题8.9
- int fileLineToVector(const string &path,vector<string> &strVec)
- {
- ifstream in(path.c_str());
- string line;
- while (getline(in,line))
- {
- strVec.push_back(line);
- }
- in.close();
- if (in.eof())
- return 2;
- if (in.fail())
- return 4;
- if (in.bad())
- return 1;
- return 0;
- }
- int main()
- {
- string path("/home/xiaofang/c++primer/code/c++14/input");
- vector<string> strVec;
- fileLineToVector(path,strVec);
- for (vector<string>::const_iterator iter = strVec.begin();iter != strVec.end(); ++iter)
- {
- cout << *iter << endl;
- }
- }
- //8.10
- int fileWordToVector(const string &path,vector<string> &strVec)
- {
- ifstream in(path.c_str());
- string word;
- while (in >> word)
- {
- strVec.push_back(word);
- }
- in.close();
- if (in.eof())
- return 2;
- if (in.fail())
- return 4;
- if (in.bad())
- return 1;
- return 0;
- }
5、文件模式
每个fstream类都定义了一组表示不同模式的值,用于指定流打开的不同模式。可用位操作符设置一个或多个模式。
in
打开文件做读操作
out
打开文件做写操作
app
在每次写之前找到文件尾
ate
打开文件后立即将文件定位在文件尾
trunc
打开文件时清空已存在的文件流
binary
以二进制模式进行 IO操作
out、trunc和app模式只能用于指定ofstream或fstream对象的关联工作;in模式只能用于指定ifstream或fstream对象的关联工作;所有的文件都可以用ate或binary模式打开,ate模式只在打开时有效!ate模式只在打开时有效:文件打开后将定位在文件结尾。以binary模式打开的流则将文件以字节序列的形式处理,而不解释流中的字符。
默认时,与ifstream流对象关联的文件将以in模式打开,该模式允许文件做读的操作:与ofstream关联的文件则以out模式打开,使文件可写。以out模式打开的文件会被清空:丢弃该文件存储的所有数据。
从效果来看,为ofstream对象指定out模式等效于同时指定了out和trunc模式。
对于ofstream打开的文件,要保存文件中已存在的数据,唯一方法是显示的指定app模式打开:
- ofstream outfile("file1");
- //与上一条语句作用相同
- ofstream outfile("file1",ofstream::out | ofstream::trunc);
- ofstream outfile_app("file2",ofstream::app);
6、对同一个文件做输入和输出运算
默认情况下,fstream对象以in和out模式同时打开。当文件同时以in和out打开时不清空,而如果打开fstream所关联的文件时,只使用out模式,而不指定in模式,则文件会被清空。如果以trunc模式打开,则无论是否指定in模式,文件同样会被清空。
- fstream InOut("file");
- //作用相同
- fstream InOut("file",fstream::in | fstream::out);
7、模式是文件的属性而不是流的属性
每次打开文件都会设置模式:
- ofstream outFile;
- outFile.open("scratchpad",ofstream::out);
- outFile.close();
- outFile.open("precious",ofstream::app);
- outFile.close();
- outFile.open("out");
只要调用 open函数,就要设置文件模式,其模式的设置可以是显式的也可以是隐式的。如果没有指定文件模式,将使用默认值。
8、打开模式的有效组合
out
打开文件做写操作,删除文件中已有的数据
out | trunc
与 out模式相同
out | app
打开文件做写操作,在文件尾写入
in
打开文件做读操作
in | out
打开文件做读、写操作,并定位于文件开头处
in | out | trunc
打开文件做读、写操作,删除文件中已有的数据
上述所有打开模式组合还可以添加ate模式,对这些模式添加ate只会改变文件打开时的初始定位,在第一次读或写之前,将文件定位于文件末尾处。
9、一个示例程序
- ifstream &open_file(ifstream &in,const string &str)
- {
- in.close();
- in.clear();
- in.open(str.c_str(),ifstream::in);
- return in;
- }
由于不确定流in的状态,因此首先调用close和clear将这个流设置为有效状。最后返回的in要么已经与指定文件绑定,要么处于错误状态。
- //P256 习题8.13
- ofstream &open_file_out(ofstream &out,const string &str)
- {
- out.close();
- out.clear();
- out.open(str.c_str(),ofstream::out | ofstream::app);
- return out;
- }
- //习题8.14
- ifstream &open_file_in(ifstream &in,const string &str)
- {
- in.close();
- in.clear();
- in.open(str.c_str(),ifstream::in);
- return in;
- }
- ofstream &open_file_out(ofstream &out,const string &str)
- {
- out.close();
- out.clear();
- out.open(str.c_str(),ofstream::out | ofstream::app);
- return out;
- }
- int main()
- {
- ifstream in;
- ofstream out;
- open_file_in(in,"/home/xiaofang/c++primer/code/c++14/input");
- open_file_out(out,"/home/xiaofang/c++primer/code/c++14/output");
- string str;
- while (in >> str)
- {
- out << str << endl;
- }
- }
二、字符串流
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对象,s是string类型的对象
strm.str();
返回 strm中存储的string类型对象
strm.str(s);
将string类型的s复制给strm,返回void
1、stringstream对象的使用
- string line,word;
- while (getline(cin,line))
- {
- istringstream stream(line);
- while (stream >> word)
- {
- // do per-word ...
- }
- }
将一个istringstream对象与所读取的行绑定起来,这样只需使用普通的string输入操作符即可读出每行中的单词。
2、stringstream提供的转换和/或格式化
stringstream对象的一个常见用法是,需要在多种数据类型之间实现自动格式化时使用该类类型。或反之。sstream输入和输出操作可自动地把算术类型转化为相应的string表示形式,反过来也可以。
- // 一个数值型数据集合, 要获取它们的 string 表 示形式
- ostringstream format_massage;
- int val1 = 512,val2 = 1024;
- format_massage << "val1: " << val1 << '\n'
- << "val2: " << val2 << endl;
- cout << format_massage.str() << endl;
- //反过来
- istringstream input_istring(format_massage.str());
- int val3,val4;
- string tmp;
- input_istring >> tmp >> val3 >> tmp >> val4;
- cout << val3 << endl;
- cout << val4 << endl;
为了读取input_string,必须把该string对象分解为若干部分。为了得到它们,必须读取(和忽略)处于所需数据周围的标号。
一般情况下,使用输入操作符读string时,空白符将会忽略,于是,在读与format_message关联的string时,忽略其中的换行符。
- //综合
- stringstream massage;
- int val1 = 512,val2 = 1024;
- massage << "val1: " << val1 << '\n'
- << "val2: " << val2 << endl;
- cout << massage.str() << endl;
- int val3,val4;
- string tmp;
- massage >> tmp >> val3 >> tmp >> val4;
- cout << val3 << endl;
- cout << val4 << endl;
- //P258 习题8.15
- istream &get(istream &in)
- {
- string str;
- while (in >> str,!in.eof())
- {
- if (in.bad())
- {
- throw runtime_error("IO stream corrupted");
- }
- else if (in.fail())
- {
- cerr << "bad data,try again" << endl;
- in.clear();
- in.ignore(200,' ');
- continue;
- }
- cout << str << '\t';
- }
- cout << endl;
- return in;
- }
- int main()
- {
- // freopen("input","r",stdin);
- string line;
- getline(cin,line);
- line += ' ';
- stringstream isstr(line);
- get(isstr);
- }
- //习题8.16
- int main()
- {
- ifstream infile("/home/xiaofang/c++primer/code/c++14/input");
- vector<string> lineVec;
- string line,word;
- while (getline(infile,line))
- {
- lineVec.push_back(line);
- }
- for (vector<string>::const_iterator iter = lineVec.begin(); iter != lineVec.end(); ++iter)
- {
- istringstream isstream(*iter);
- while (isstream >> word)
- {
- cout << word << '\t';
- }
- cout << endl;
- }
- stringstream isstream;
- for (vector<string>::const_iterator iter = lineVec.begin(); iter != lineVec.end(); ++iter)
- {
- isstream.str(*iter);
- while (isstream >> word)
- {
- cout << word << endl;
- }
- isstream.clear();
- }
- }
- C++ Primer 学习笔记_26_标准I/O库(续) --文件的输入与输出、字符串流
- C++ Primer 学习笔记_25_标准I/O库 --面向对象的标准库、条件状态、输出缓冲区的管理
- Cpp Primer<<学习IO标准库--输出缓冲区的管理、文件输入与输出_6
- 【C++ Primer】【学习笔记】【第八章】标准IO库之:文件的输入和输出
- 【C++ Primer】【学习笔记】【第八章】标准IO库之:字符串流
- Cpp Primer<<学习IO标准库--文件模式、字符串流_7
- 底层I/O(无缓冲)与 C标准I/O 学习笔记
- linxu C 学习笔记(三):标准I/O库
- C++ Primer学习笔记:标准输入/输出
- 黑马程序员——I/O输入与输出 学习笔记(一)
- java系统学习(十一) --------输入与输出(I/O)
- Linux&C语言文件学习笔记(四):文件I/O与系统API续
- [UNIX C学习笔记] 输入/输出【标准输入--->>标准输出】
- I/O口的输入与输出
- C++ Primer学习笔记——$8 标准I/O库
- 文件I/O与标准I/O的区别
- 第八章 标准IO库(文件的输入输出、字符串流)
- C语言学习笔记之字符I/O(getchar()函数与putchar()函数)
- C++ Primer 学习笔记_25_标准I/O库 --面向对象的标准库、条件状态、输出缓冲区的管理
- Gallery自动循环滚动以及手动滚动的平滑切换
- 贪心 Codeforces584C Marina and Vasya
- DroidDraw UI设计软件开发Android GUI应用程序
- Google宣布支持Vulkan作为Android的底层图形API
- C++ Primer 学习笔记_26_标准I/O库(续) --文件的输入与输出、字符串流
- Ajax+Spring MVC实现跨域请求(JSONP)
- Android MVP结构的初步认识
- 简历的重点是抓人
- Linux中通过locale来设置字符集
- jmeter安装启动报错:Not able to find Java executable or version. Please check your Java installation
- Linux之解决你的网络问题
- C语言文件与目录(五)文件锁
- HTML canvas原生js实现鼠标画图