天天看點

C++Primer 學習筆記 第八章 IO庫

//8.1 IO類
//到目前為止,我們已經使用過的IO類型和對象都是操縱char資料的。預設情況下,這些對象都是關聯使用者的控制台視窗的。
//當然,我們不能限制實際應用程式僅從控制台視窗進行IO操作,應用程式常常需要讀寫命名檔案。而且,使用IO操作處理string
//中的字元會很友善。此外,應用程式還可能讀寫需要寬字元支援的語言。


//8.1.1 IO對象無拷貝或指派

//8.1.2條件狀态

//查詢流的狀态
//管理條件狀态

//8.1.3管理輸出緩沖
//每個輸出流都管理一個緩沖區,用來儲存程式讀寫的資料。例如,如果執行下面的代碼
//os<<"please enter a value: ";
//文本串可能立即列印出來,但也有可能被作業系統儲存在緩沖區中,随後再列印。有了緩沖機制,作業系統就可以将程式的
//多個輸出操作組合成單一的系統級寫操作。由于裝置的寫操作可能很耗時,允許系統将多個輸出操作組合成單一的系統級寫操作。
//導緻緩沖重新整理的原因有很多。

//1.程式正常結束,作為main函數的return操作的一部分,緩沖重新整理被執行。
//2.緩沖區滿時,需要重新整理緩沖,而後新的資料才能繼續寫入緩沖區。
//3.我們可以使用操縱符如endl來顯式重新整理緩沖區。
//4.再每個輸出操作之後,我們可以用操作符unitbuf設定流的内部狀态,來清空緩沖區。預設情況下,對cerr是設定unitbuf的,是以寫到cerr
//  的内容都是立即重新整理的。
//5.一個輸出流可能被關聯到另一個流。在這種情況下,當讀寫被關聯的流時,關聯到的流的緩沖區會被重新整理。例如,預設情況下,cin和cerr都關聯到cout。
//是以,讀cin或寫cerr都會導緻cout的緩沖區被重新整理。


//重新整理輸出緩沖區
#include "iostream"
#include"fstream"
#include "vector"
#include"string"
#include "sstream"


using namespace std;
int main81() {
	cout << "hi!" << endl;
	cout << "hi!" << flush;
  	cout << "hi" << ends;
	cout << unitbuf;
	cout << "hi";
	system("pause");
	return 0;
}

//關聯輸入流和輸出流
//當一個輸入流被鍛煉到一輸出流時,任何試圖從輸入流讀取資料的操作都會先重新整理關聯的輸出流。
//标準庫将cout和cin關聯在一起。
//cin>>ival;

int main82() {
	cin.tie(&cout);//僅僅是用來展示:标準庫将cin和cout關聯在一起
	//old_tie指向關聯到cin的流(如果有的話)
	ostream *old_tie = cin.tie(nullptr);//cin不再與其他流關聯
	cin.tie(&cerr);//讀取cin會重新整理cerr而不是cout
	cin.tie(old_tie);//重建cin和cout間的關聯
	return 0;
}

//8.2檔案輸入輸出
//頭檔案fstream定義了三個類型來智齒檔案IO:ifstream從一個給定檔案中讀取資料,ofstream從一個給定檔案中寫入資料,以及fstream可以讀寫給定檔案。

//8.2.1使用檔案流對象
//當我們想要讀寫一個檔案時,可以定義一個檔案流對象,并将對象與檔案關聯起來,每個檔案流都定義了一個名為open的成員函數
//他完成一些系統相關的操作,來定位給定的檔案,并視情況打開位讀或寫模式
//建立檔案流對象時,我們可以提供檔案名。如果提供了一個檔案名,則open會被自動調用。
//ifstream in(ifile);    //構造一個ifstream并打開給定檔案
//ofstream out;        //輸出檔案流并未關聯到任何檔案

int main83() {
	//ifstream in("F:/FWNfiles/C++回爐/C++重造/io.txt");
	ofstream out("F:/FWNfiles/C++回爐/C++重造/io.txt");
	out << "周六保證不學習,周日學習不保證!";
	out << endl;
	out << "星期六保證不休息,星期天休息不保證!";
	out << endl;
	out << "運作之後就沒有了?";
	out << endl;
	ifstream in("1.txt");
	ofstream output("2.txt");
	output << "love" << endl;
	ifstream input("2.txt");
//	system("pause");
	return 0;
}


//8.2.2檔案模式
//每個流都有一個關聯的檔案模式,用來指出如何使用檔案。表8.4列出了檔案模式和他們的含義

//以out模式打開檔案會丢棄已有資料
//預設情況下,當我們打開一個ofstream時,檔案的内容會被丢棄。阻止一個ofstream清空給定檔案内容的方法是同時指定app模式
int main84() {
	//在這幾條語句中,file1都被截斷
	ofstream out("file1.txt");//隐含以輸出模式打開檔案并截斷檔案
	ofstream out2("file1.txt", ofstream::out);//隐含截斷檔案
	ofstream out3("file1.txt", ofstream::out | ofstream::trunc);
	out << "1";
	out3 << "3";
	out2 << "2";
	out << "4";
	//為了保留檔案内容,我們必須顯式指定app模式
	ofstream app("file2.txt", ofstream::app);//隐含為輸出模式
	app << "1";
	ofstream app2("file2.txt", ofstream::out | ofstream::app);
	app2 << "2";
	ofstream ate("file2.txt", ofstream::out | ofstream::ate);
	ate << "上山打老虎";

	return 0;
}


//8.3string流
//sstream頭檔案定義了三個類型來智齒記憶體IO,這些類型可以向string寫入資料,從string讀取資料,就香string是一個IO流一樣
//isstring從string讀取資料,ostringstream向string寫入資料,而頭檔案stringstream既可以從string讀資料也可以向string寫資料


//8.3.1使用istringstream
//假定又這樣一個例子,假定有一個檔案,列出了一些人和他們的電話号碼。某些人隻有一個号碼,而另一些人則有多個——家庭電話
//工作電話,行動電話。我們的輸入檔案看起來可能是這樣
//morgan 201552368 8625550123
//derw   9735550130
//iee 6095550132 20155550175 8005550000

//檔案中每條記錄都是以一個人名開始,後面跟随一個或多個電話号碼。
//我們首先定義一個簡單的類來描述輸入資料:

struct  PresonInfo
{
	string name;
	vector<string> phones;
};


int main85() {
	string line, word;
	vector<PresonInfo> peoole;
	while (getline(cin,line))
	{
		PresonInfo info;
		istringstream record(line);
		record >>info.name;
		while (record>>word)
		{
			info.phones.push_back(word);
			peoole.push_back(info);
		}
	}
	system("pause");
	return 0;
}

//8.3.2使用ostringstream
//當我們逐漸構造輸出,希望最後一起列印時,ostringstream是很有用的。例如,對上一節的例子,我們可能逐個驗證
//電話号碼并逐個驗證電話并改變其格式。如果所有号碼都是有效的,我們希望輸出一個新的檔案,包含改變格式後的号碼。
//對于那些無效的号碼,我們不會将他們輸出到新檔案中,而是列印一條包含人名和無效号碼的錯誤資訊。

//由于我們不希望輸出有無效電話号碼的人,是以對每個人,直到驗證完所有電話号碼後才可以進行輸出操作。但是,我們可以先将輸出内容
//寫入到一個記憶體ostringstream中。

int main() {
	string line, word;
	vector<PresonInfo> people;
	while (getline(cin, line))
	{
		PresonInfo info;
		istringstream record(line);
		record >> info.name;
		while (record >> word)
		{
			info.phones.push_back(word);
			people.push_back(info);
		}
	}
	for (const auto& entry:people)
	{
		ostringstream formatted, badNums;//每個循環步建立的對象
		for (const auto& nums:entry.phones)
		{
			//if (!valid(nums))
			{
				badNums << " " << nums;
			}
			//else
			//	(formatted<<" "<<format(nums))
		}
		if (badNums.str().empty())
		{
			//os << entry.name << " " << formatted.str() << endl;
		}
		else
		{
			cerr << "input error: " << entry.name << " invalid number(s)" << badNums.str() << endl;
		}
	}



	system("pause");
	return 0;
}

//在此程式中,我們假定已有兩個函數,valid和format,分别完成電話号碼驗證和改變格式的功能。
           

繼續閱讀