为了支持不同的IO处理操作,C++定义了一系列IO类型,如下表
头文件 | 类型 |
---|---|
iostream | istream,从流读取数据; ostream,向流写入数据; iostream,读写流 |
fstream | ifstream,从文件读取数据; ofstream,向文件写入数据; fstream,读写文件 |
sstream | istringstream,从string读取数据;ostringstream,向string写入数据;stringstream,读写string |
IO对象无拷贝或赋值
我们不能拷贝或对IO对象赋值:
ofstream out1,out2;
out1 = out2; //wrong
ofstream print(ofstream); //wrong,不能初始化ofstream参数
out2 = print(out2); //wrong:不能拷贝流对象
由于不能拷贝IO对象,因此我们也不能讲形参或返回类型设置为流类型。进行IO操作的函数通常以引用方式传递和返回流。读写一个IO对象会改变其形态,因此传递和返回的引用不能是const的。
管理输出缓冲
每个输出流都管理一个缓冲区,用来保存程序读写的数据。例如,如果执行下面的代码
os<<"please enter a value:";
文本串可能立即打印出来,也可能保存在缓冲区中,稍后打印。导致缓冲刷新的原因有:
- 程序正常结束,作为main函数的return操作的一部分,缓冲刷新被执行。
- 缓冲区满时
- 使用操纵符如endl等,显式刷新
- 使用操纵符unitbuf设置
- 一个输出流可能关联到另一个流。在这种情况下,当读写被关联的流时,关联到的流的缓冲区会被刷新。例如,在默认情况下,cin和cerr都关联到cout。
cout<<"hi!"<<endl; //输出hi!和一个换行,然后刷新缓冲区
cout<<"hi!"<<flush; //输出一个hi!,然后刷新缓冲区,不附加任何额外字符
cout<<"hi!"<<ends; //输出hi!和一个空字符,然后刷新缓冲区
cout<<unitbuf; //所有输出操作后都会立即刷新缓冲区
//任何输出都立即刷新,无缓冲
cout<<nounitbuf; //回归到正常的缓冲方式
使用文件流对象
ifstream in(ifile); //构造一个ifstream,并打开给定文件
ofstream out; //输出文件流为关联到任何文件
如果我们定义了一个空文件流对象,可以随后调用open来将它与文件关联起来
out.open(ifile+".copy");
如果调用open失败,failbit会被置位。因为调用open可能失败,进行open是否成功的检测通常是个好习惯:
if(out)
还要记得关闭
in.close();
in.open(ifile+"2");
注:当一个fstream对象被销毁时,close会自动被调用。
string流
使用istringstream
考虑一个例子,记录员工信息,有些人的电话可能有多个:
morgan 20151123 12354234
drew 23141334
lee 1356782211 1238412334 1231249999
文件中每条记录都以一个人名开始,后面跟随一个或多个电话号码。我们首先定义一个简单的类来描述输入数据:
struct PersonInfo{
string name;
vector<string> phones
}
我们开始读取数据
string line,word; //分布保存来自输入的一行和单词
vector<PersonInfo>people; //保存来自输入的所以记录
//逐行从输入读取数据,直至cin遇到文件尾(或者其他错误)
while(getline(cin,line)){
//getline从保准输入读取整条记录。如果getline调用成功,
//那么line中将保存着从输入文件而来的一条记录。
PersonInfo info;
istringstream record(line);//将记录绑定到刚读入的行,这样就可以用输入运算操作符读取元素啦
record>>info.name;
while(record>>word)
info.phones.push_back(word);
people.push_back(info);
}
从一个string中读取数据,当string中的数据全部读出后,同样会触发“文件结束”信号,在record上的下一个输入操作会失败。
使用ostringstream
类似,用<<