一、面向对象的标准库
C++的输入输出都是由标准库提供。标准库中还定义了一族类型,支持对文件和控制窗口等设备的读写。
比如说,IO类型在三个独立的头文件中定义:
iostream定义读写控制窗口的类型;
fstream定义读写已命名文件的类型;
sstream定义的类型则用于读写存储在内存中的string对象。
IO标准库类型和头文件 |
头文件 类型 |
iostream istream从流中读取 ostream 写到流中去 iostream 对流进行读写;从istream和ostream派生而来 fstream ifstream从文件中读取;由istream派生而来 ofstream 写到文件中去;由ostream派生而来 fstream 读写文件;由iostream派生而来 sstream istringstream从string对象中读取;由istream派生而来 ostream stream写到string对象中去;由ostream派生而来 stringstream 对string对象进行读写;由iostream派生而来 |
程序可以对控制窗口,已命名的文件和内存进行IO。
注意:1.迄今所描述的流类读写的都是由char类型组成的流。
2.标准库类型不允许复制和赋值操作(error:ofstream out1=out2)
二、条件状态
我们需要知道IO标准库是如何管理其缓冲区及其流状态的相关内容。那以下的条件状态就是用来标记给IO对象是否处于可用状态或者是碰到了哪些特定的错误。
IO标准库的条件状态 |
strm::iostate 机器相关的整型名,由各个iostream类定义,用于定义条件状态 strm::badbit strm::iostate类型的值,用于指出被破坏的流 strm::failbit strm::iostate类型的值,用于指出失败的IO操作 strm::eofbit strm::iostate类型的值,用于指出流已经到达文件结束符 s.eof() 如果设置了流s的eofbit值,则函数返回true s.fail() 如果设置了流s的failbit值,则函数返回true s.bad() 如果设置了流s的badbit值,返回true s.good() 如果流s处于有效状态,返回true s.clear() 将流s中的所有状态值都重设为邮箱状态 s.clear(flag) 将流s中的某个条件状态设置为有效 s.setstate(flag) 给流s添加指定状态。 s.rdstate() 返回流s的当前条件 |
// C++文件读写.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include<iostream> #include<fstream> #include<cstdlib> using namespace std; int main() { ofstream fin; fin.open("file1.txt");//创建文件file1.txt int row,col,i,j,number; cout<<"Enter data row and col:"; cin>>row>>col; //按照行列写入数据到 file.txt中 cout<<"Enter data:"<<endl; for(i=0;i<row;i++) { for(j=0;j<col;j++) { cin>>number; fin<<number<<" ";//写入数据到文件 } fin<<"\n"; } fin.close(); //写入数据完毕 ifstream infile; infile.open("file1.txt");//打开文件file1.txt fin.open("file2.txt");//创建文件file2.txt if(!infile.is_open()) {//若打开失败 cout<<"open file1 failed!"<<endl; exit(EXIT_FAILURE); } //infile>>number;//开始从文件中读取数据 int sum=0,count=0;//sum用于保存每一行的和,count用于区分一行结束,以便计算均值 sum+=number; while(infile>>number,!infile.eof()) {//没到文件尾 ++count; if(count%col==0) {//一行读取完毕 fin<<sum<<" "<<(double)sum/col<<endl;//将计算结果写入file2.txt sum=0;//将保存行的和置为零 } else { infile>>number;//读取数据到number中 sum+=number;//实现累加求和 } } infile.close(); fin.close(); //写入数据读数据完毕,关闭文件流 return 0; }
有个疑问:绿色标注的两个地方,效果不一样。条件状态到底有什么用?你自己想想,如果流处于错误状态,你是不是应该知道是哪类错误,是IO设备错误还是其他错误。
1.条件状态
IO类定义了三个iostate类型的常量值
badbit:系统级故障,无法恢复的读写错误。表示流已经不能使用
failbit:可恢复的故障
eofbit:遇到了文件结束符
2.流状态的查询与控制
int ival; while(cin>>ival,!cin.eof()){ if(cin.bad())//输入流corrupted throw runtime_error("IO stream corrupted"); if(cin.fail()){ cerr<<"bad data, try again"; cin.clear(istream::goodbit); cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');//ignore bad input continue; } // ok to process ival }
3.条件状态的访问
istream::iostate old_state = cin.rdstate();
cin.clear();
process_input(); //use cin
cin.clear(old_state); // now rest cin to oldstate
4.多种状态的处理
is.setstate(ifstream::badbit | ifstream::failbit)
将对象is的failbit和badbit位同时打开。
三、输出缓冲区的管理
每个IO对象管理一个缓冲区,用于存储程序读写的数据。
下面几种情况将导致缓冲区内容被刷新,即写到控制设备或文件中。
1)程序正常结束。main函数一部分,缓冲区清空。
2)缓冲区满了,在写入之前刷新;
3)用操作符显示的刷新缓冲区,如endl;
4)每次输出操作执行完后,用unitbuf操作符设置流的内部状态,清空缓冲区;
5)可将输出流与输入流关联起来(tie)。这样,读输入流的时候刷新其相关的输出缓冲区。
1.输出缓冲区的刷新
cout<<"hi"<<flush;//flush buffer不添加数据 cout<<"hi"<<ends;//添加一个null,flush buffer cout<<"hi"<<endl;//插入一个新行,flush buffer
2.unitbuf操作符
nounitbuf用于将流恢复为使用正常的,由系统管理的缓冲区刷新方式。cout<<unitbuf<<"first"<<"second"<<nounitbuf 等价于 cout<<"first"<<flush<<"second"<<flush
3.将输入和输出绑在一起
一般用tie函数。
四、文件的输入和输出
fstream头文件定义了三种支持文件IO的类型:
1) ifstream,由istream派生而来,提供读文件的功能;
2) ofstream,由ostream派生而来,提供写文件的功能;
3) fstream,由iostream派生而来,提供读写同一个文件的功能。
另外,fstream类型还自定义了两个新操作-open()和close()
<一> 文件流对象的使用
将要定义的对象和需要读写的文件(ifile和ofile)进行绑定。
注意:IO标准库使用的是C风格的字符串,而不是C++ string类型的字符串。因此你需要通过c_str()进行转换。ifstream infile(ifile.c_str()); ofstream outfile(oflile.c_str()); 或者 ifstream infile; ofstream outfile; infile.open("in"); outfile.open("out");
1.检查是否成功
2.将文件流与新文件重新捆绑if(!infile){ cerr<< "error: unable to open input file:" <<ifile<<endl; return -1; }
3.清除文件流的状态ifstream infile("in"); infile.close(); infile.open("next");
其中,需要读取vector对象中的fileswhile( it != files.end){ ifstream input(it->c_str()); // if the file ok, process input if(!input) break; while(input>>s) process(s); ++it; }
ifstream input; vector<string>::const_iterator it=fiels.begin(); while( it != files.end()){ input.open(it->c_str()); // if the file ok, process input if(!input) break; while(input>>s) process(s); input.close(); input.clear(); ++it; } 注意: 1)定义一个IO对象; 2)通过close()和clear()操作关闭和清空文件流; 3)如果需要重用文件流读写多个文件,必须在读另一个文件之前调用clear清除该流的状态。 <二>文件模型 文件模式 in 打开文件做读操作out 打开文件做写操作app在每次写之前找到文件尾ate打开文件后立即将文件定位到文件尾trunc打开文件时清空已存在的文件流binary以二进制模式进行IO操作 例如: ofstream outfile1("file1",ofstream::out | ofstream::trunc) ofstream appfile("file2",ofstream::app); 注意:模式是文件的属性而不是流的属性 下面是打开模式的有效组合 文件模式的组合 out 打开文件做写操作,删除文件中已存在的数据 out | app 打开文件做写操作,在文件尾写入 out | trunc 与out模式相同 in 读操作 in | out 打开文件做读写操作,并定位于文件开头处 in | out | trunc 打开文件做读写操作,删除文件中已经存在的数据 下面是一个打开并检查输入文件的程序 ifstream& open_file(ifstream &in, const string &file) { in.close(); in.clear(); in.open(file.c_str()); return in; }