C++中的iostream、fstream、sstream(附测试代码)

下面介绍C++中的iostream、fstream、sstream的使用方法,内容出自C++primer第八章内容。
一、 IO类
1.三种IO类型
C++中的iostream、fstream、sstream(附测试代码)_第1张图片

加w的类型为对宽字符wchar_t的操作,如wistream、wostream中的wcin、wcot、werror。
ifstream和isteingstream都继承自istream,可使用cin的功能(如>>和getline等)。ofstream和ostringstream都继承自ostream,可使用cout的功能
2.不能拷贝或对IO对象赋值:
在这里插入图片描述

不能将形参后返回值设置为流类型,通常以引用方式传递和返回流进行IO操作,并且返回的引用不能为const,因为读写IO会改变其状态。
3.条件状态
IO类定义的函数和标志,便于访问和控制流条件状态。
C++中的iostream、fstream、sstream(附测试代码)_第2张图片C++中的iostream、fstream、sstream(附测试代码)_第3张图片
IO流读写错误时(比如期望输入int,结果输入了字符或文件结束标志),后续IO操作都会失败。为保证流对象的状态正确,一般将它当作条件使用,如果输入成功,流保持有效状态,条件为真。

 while(cin>>word)

可通过上面表中的函数查询标志位状态,如操作good在所有错误位未置位情况下返回true,而bad\fail\eof则在对应错误位置置位时返回true。
无参数clear可以清除所有错误标志位,执行后调用good会返回true。带参数clear接收iostate值,表示流的新状态,可以通过该功能复位指定状态位。
3.管理输出缓冲
每个输出流都管理一个缓冲区用来保存程序读写的数据,系统可将多个输出组合为单一的设备写操作以提升性能。导致缓冲刷新(数据真正写入设备或文件)包括:程序正常结束、缓冲区满、endl、unitbuf、一个输出流可能被关联到另一个流。如果程序异常终止,输出缓冲区不会被刷新。
在这里插入图片描述
在这里插入图片描述
C++中的iostream、fstream、sstream(附测试代码)_第4张图片
二、 文件输入输出

  1. 文件读写
    Ifstream从文件中读取数据,ofstream向文件写入数据,fstream读写给定文件。这些类型继承了iostream类型的<< 、>>、getline等行为,还增加了下表中的操作:
    C++中的iostream、fstream、sstream(附测试代码)_第5张图片

通过定义文件流对象可将对象和文件关联起来,通过open成员函数定位给定文件并打开为读或写模式,也可在创建文件流对象提供文件名,然后open会被自动调用。

ofstream out1;
out1.open("filename.txt", ios::in | ios::binary);//打开文件方法1
//ofstream out("filename.txt");//打开文件方法2 在构造函数直接调用了open函数

通常需要对open是否成功进行检测:if (out1.is_open())。
在要求使用基类对象的地方可使用继承类型对象替代,iostream类型引用或指针的参数可用fstream后sstream类型调用。
C++中的iostream、fstream、sstream(附测试代码)_第6张图片

  1. 文件模式
    打开文件方式如下:
    C++中的iostream、fstream、sstream(附测试代码)_第7张图片

指定文件模式限制:
C++中的iostream、fstream、sstream(附测试代码)_第8张图片

Ifstream关联文件默认in模式,ofstream关联文件默认out模式,fstream关联文件默认in和out模式。

  1. 以out模式打开文件会丢弃已有数据(很重要)
    默认情况ofstream打开文件,内容会被截断清空,阻止该情况发生需要指定app模式。
    C++中的iostream、fstream、sstream(附测试代码)_第9张图片

(删除文件:将文件的目录项删掉并释放磁盘块,截断文件:将文件中的部位数据删掉 不删除目录项 )
三、 String流
istringstream从string中读取数据,ostringstream向string中写入数据,头文件stringstream既可读又可写string数据。Sstream也继承了iostrea,还增加了下面的操作:
C++中的iostream、fstream、sstream(附测试代码)_第10张图片

  1. istringstream
    当我们工作是对整行文本或行内单个单词进行处理时,通常可以考虑istringstream。如有下面的数据,姓名后跟着若干号码:
anmy 2345 56437
daga 23456 67543
hsagg 26789 8765

定义简单地类描述输入数据:

 struct PersonInfo{
	string name;
	vector phones;
};

程序会读取数据文件并创建PersonInfo的vector,,vector中每个元素对应文件中的一条记录,在循环中处理输入输出,每个循环读取一条记录。如下所示。

string line, word;
vector<PersonInfo> people;
while (getline(cin,line)){
	PersonInfo info;
	istringstream record(line);
	record >> info.name;
	while (record >> word){
		info.phones.push_back(word);
	}
	people.push_back(info);
}

通过getline从标准输入读取整条记录,如果调用成功,line中将保存着从输入文件而来的一条记录。在循环中定义了局部PersonInfo对象保存当前记录,接下来将istringstream和刚刚读取的文本绑定,然后通过运算符记录当前中的每个元素。
2. ostringstream
当逐步构造输出,希望最后一起打印时,采用ostringstream很有用。比如对上面的例子只输出有效的电话号码。对无效的号码不会将它们输出到新文件中,而是打印一条包含人名和无效号码的错误信息。

for (const auto &entry : people) {
	ostringstream formatted, badNums;
	for (const auto &nums : entry.phones){
		if (strcmp(nums.c_str(), "8766") < 0)
			badNums << "bad " << nums;
		else {
			formatted << "ok " << nums;
		}
	}
	if (badNums.str().empty())
		cout << entry.name << " " << formatted.str() << endl;
	else
		cerr << "input error:" << entry.name << "invalid number  " << badNums.str() << endl;
}

C++中的iostream、fstream、sstream(附测试代码)_第11张图片

#include
#include
#include
#include
using namespace std;
const char * filename = "test.txt";
struct PersonInfo{
	string name;
	vector<string> phones;
};
int main() {
	char buffer[1024];

	/***************************文本文件读写*******************************/
	ofstream out1;
	out1.open("test.txt");//ofstream默认情况或不指定app模式下打开文件会导致文件内容丢失
	out1.open(filename, ios::out | ios::app);//打开文件方法1,指定app模式
	ofstream out1("test.txt", ios::out | ios::app);//打开文件方法2 在构造函数直接调用了open函数
	if (out1.is_open()) {
		out1 << "hi!\n";
		out1.close();
	}
	else
		cout << "error opening file";
	ifstream in(filename, ios::in);
	if (!in.is_open()) {
		cout << "error opening file"; exit(1);
	}

	while (!in.eof()) {
		in.getline(buffer,20);//getline 第二个参数不能比实际行数小
		cout << buffer << endl;
	}
	//in.close();////当指针直到eof后,若要重置指针位置到开头,需要采用下面两种方法
	//in.open("test.txt", ios::in);//方法1:要重新打开文件后才能将指针重定位到开始位置
	in.clear(); //方法2:对流状态标志进行清除
	long length1, length2;
	in.seekg(0, ios::beg);
	length1 = in.tellg();
	in.seekg(0,ios::end);//将get指针移动到beg文件结束位置
	length2 = in.tellg();
	in.close();
	cout << "len1:" << length1 << endl;
	cout << "len2:" << length2 << endl;
	cout << "len:" << length2 - length1 << " bytes" << endl;
	/***************************二进制文件读写*******************************/
	fstream binInOut(filename,ios::in|ios::ate|ios::binary);
	char * buffer1;
	long size = binInOut.tellg();
	binInOut.clear();
	binInOut.seekg(0,ios::beg);
	buffer1 = new char[size];
	binInOut.read(buffer1, size);
	cout <<"size:"<<size <<" buffer1:" << buffer1 << endl;//不知道为什么末尾会多出乱码
	//cout << "buffer1:" << static_cast(buffer1) << endl;
	binInOut.close();
	delete[] buffer1;

	/***************************字符串读写*******************************/
	/* 输入字符串数据
	anmy 2345 56437
	daga 23456 67543
	hsagg 26789 8765
	输入完成后 回车+ctrl + c
	*/
	string line, word;
	vector<PersonInfo> people;
	while (getline(cin,line)){
		PersonInfo info;
		istringstream record(line);
		record >> info.name;
		while (record >> word){
			info.phones.push_back(word);
		}
			
		people.push_back(info);
	}
	
	ofstream out1("test.txt", ios::out | ios::app);//ofstream 写入数据
	if (out1.is_open()) {
		for (int i = 0; i < people.size(); i++){
			for (int j = 0; j < people.at(i).phones.size(); j++){
				out1 << people.at(i).name << ends << people.at(i).phones.at(j) << endl;
				cout << people.at(i).name << ends << people.at(i).phones.at(j) << endl;
			}
		}
		out1.close();
	}
	for (const auto &entry : people) {
		ostringstream formatted, badNums;
		for (const auto &nums : entry.phones){
			if (strcmp(nums.c_str(), "8766") < 0)
				badNums << "bad " << nums;
			else {
				formatted << "ok " << nums;
			}
		}
		if (badNums.str().empty())
			cout << entry.name << " " << formatted.str() << endl;
		else
			cerr << "input error:" << entry.name << "invalid number  " << badNums.str() << endl;
	}
	return 0;
}

你可能感兴趣的:(C++primer)