C++中的iostream、fstream、sstream(附測試代碼)

下面介紹C++中的iostream、fstream、sstream的使用方法,內容出自C++primer第八章內容。
一、 IO類
1.三種IO類型
在這裏插入圖片描述

加w的類型爲對寬字符wchar_t的操作,如wistream、wostream中的wcin、wcot、werror。
ifstream和isteingstream都繼承自istream,可使用cin的功能(如>>和getline等)。ofstream和ostringstream都繼承自ostream,可使用cout的功能
2.不能拷貝或對IO對象賦值:
在這裏插入圖片描述

不能將形參後返回值設置爲流類型,通常以引用方式傳遞和返回流進行IO操作,並且返回的引用不能爲const,因爲讀寫IO會改變其狀態。
3.條件狀態
IO類定義的函數和標誌,便於訪問和控制流條件狀態。
在這裏插入圖片描述在這裏插入圖片描述
IO流讀寫錯誤時(比如期望輸入int,結果輸入了字符或文件結束標誌),後續IO操作都會失敗。爲保證流對象的狀態正確,一般將它當作條件使用,如果輸入成功,流保持有效狀態,條件爲真。

 while(cin>>word)

可通過上面表中的函數查詢標誌位狀態,如操作good在所有錯誤位未置位情況下返回true,而bad\fail\eof則在對應錯誤位置置位時返回true。
無參數clear可以清除所有錯誤標誌位,執行後調用good會返回true。帶參數clear接收iostate值,表示流的新狀態,可以通過該功能復位指定狀態位。
3.管理輸出緩衝
每個輸出流都管理一個緩衝區用來保存程序讀寫的數據,系統可將多個輸出組合爲單一的設備寫操作以提升性能。導致緩衝刷新(數據真正寫入設備或文件)包括:程序正常結束、緩衝區滿、endl、unitbuf、一個輸出流可能被關聯到另一個流。如果程序異常終止,輸出緩衝區不會被刷新。
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
二、 文件輸入輸出

  1. 文件讀寫
    Ifstream從文件中讀取數據,ofstream向文件寫入數據,fstream讀寫給定文件。這些類型繼承了iostream類型的<< 、>>、getline等行爲,還增加了下表中的操作:
    在這裏插入圖片描述

通過定義文件流對象可將對象和文件關聯起來,通過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類型調用。
在這裏插入圖片描述

  1. 文件模式
    打開文件方式如下:
    在這裏插入圖片描述

指定文件模式限制:
在這裏插入圖片描述

Ifstream關聯文件默認in模式,ofstream關聯文件默認out模式,fstream關聯文件默認in和out模式。

  1. 以out模式打開文件會丟棄已有數據(很重要)
    默認情況ofstream打開文件,內容會被截斷清空,阻止該情況發生需要指定app模式。
    在這裏插入圖片描述

(刪除文件:將文件的目錄項刪掉並釋放磁盤塊,截斷文件:將文件中的部位數據刪掉 不刪除目錄項 )
三、 String流
istringstream從string中讀取數據,ostringstream向string中寫入數據,頭文件stringstream既可讀又可寫string數據。Sstream也繼承了iostrea,還增加了下面的操作:
在這裏插入圖片描述

  1. istringstream
    當我們工作是對整行文本或行內單個單詞進行處理時,通常可以考慮istringstream。如有下面的數據,姓名後跟着若干號碼:
anmy 2345 56437
daga 23456 67543
hsagg 26789 8765

定義簡單地類描述輸入數據:

 struct PersonInfo{
	string name;
	vector<string> 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;
}

在這裏插入圖片描述

#include<iostream>
#include<fstream>
#include<sstream>
#include<vector>
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<const void*>(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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章