//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,分别完成電話号碼驗證和改變格式的功能。