C++中的IO庫(三)
地點:基地
時間:2014.03.20
------------------------------------------------------------------------------
一、string流簡述
前面我們已經說道,標準庫中定義IO型別的有三個標頭檔案:iostream 定義; 用於讀寫流的基本型別,fstream定義了讀寫命名檔案的型別,sstream定義了讀寫記憶體string物件的型別。其中在sstring標頭檔案中定義了三個型別來支援記憶體IO,這些型別可以向string中寫入資料,從string讀取資料,就像string是一個IO流一樣。
相關列出如下:
1. istringstream 從string讀取資料。
2. ostringstream 向string寫入資料。
3. stringstream 既可從string讀取資料也可向string寫資料。
和前面fstream一樣,sstream也是繼承自iostream,另外也有些新的東西假如,總結如下:
sstream strm; //strm是一個未繫結的stringstream對
sstream strm(s); //strm是一個sstream物件,儲存string s的一個拷貝,此建構函式explicit
strm.str(); //返回strm所儲存的string的拷貝
strm.str(s); //將string s拷貝到strm中,返回void
------------------------------------------------------------------------------
二、使用istringstream
當你想對整行文字進行處理,而其他一些工作時處理行內的單個單詞時,通常使用istringstream。
任務:假如有一個檔案,列出了一些人和他們的電話號碼,某些人只有一個號碼,而某些人則有多個:家庭電話,工作電話,行動電話。輸入檔案可能是這樣;
morgan 13332517100
drew 13336547895 13335247654
jim 13336547126 13335647856 13335267865
即檔案中每條記錄都以一個人名開始,後面跟若干個電話號碼,我們可以先定定義一個數據結構來描述:
struct PersonInfo{
string name;
vector<string> phonses;
};
有了這樣一個結構後,我們可以建立一個PersonInfo的vector。vector中的每個元素對應檔案中的一條記錄。我們可通過迴圈讀取資料,每個迴圈讀取一條記錄,然後提取個人姓名和電話號碼資訊,實現如下:
string line,word; //分別用來儲存來自輸入的一行和單詞
vector<PersonInfo> people; //儲存來自輸入的所有記錄
while(getline(cin,line)){ //逐行讀取資料直到cin遇到檔案尾或者其它錯誤
PersonInfo info; //建立一個儲存一條資料記錄的PersonInfo物件
istringstream record(line); //將記錄繫結到剛讀入的行資訊
while(record>>word) //讀取電話號碼
info.phones.push_back(word); //保持它們
people.push_back(info); //將此記錄追加到people末尾
}
這裡我們先用getline從標準輸入讀取整條記錄(一行),然後將istringstream與該條記錄進行繫結,現在我們就可以把該部分記憶體就像一個IO那樣去使用它了,可實現在一個迴圈裡,依次將資料讀入構造一個PersonInfo物件,當string資料全部讀出後,同樣也會觸發一個“檔案結束”訊號,退出迴圈,並將構造好的物件追加到vector中。
------------------------------------------------------------------------------
三、使用ostringstream
繼續延續上面的例子,現在假如我們想逐個驗證我們得到的使用者電話號碼並改變其輸出格式:有效號碼按規定輸出到一個新檔案,無效號碼則是列印人名和無效號碼的對應資訊。因此,現在我們應該先針對每條記錄先“寫入”到一個記憶體ostringstream中,驗證完所有電話號碼後才進行輸出操作。實現如下(程式中valid和format為假定已有的函式,分別完成電話號碼的驗證和改變格式的功能):
for(const auto &entry:people){ //對people中的每一項
ostringstream formatted,badNums; //每個迴圈步都建立的物件性
for(const auto &nums:entry.phonse){ //對每條記錄中的電話號碼
if(!valid(nums)){
badNums<<" "<<nums; //將數的字串形式存入badNums
}else
formatted<<" "<<format(nums); //將格式化的字串“寫入”formatted
}
if(badNums.str().empty()) //沒有錯誤的數
os<<entry.name<<" "<<formatted.str()<<endl; //列印名字和格式化的數
else //否則列印名字和錯誤的數
cerr<<"input error: "<<entry.name
<<“ invalid number(s) "<<badNums.str()<<endl;
------------------------------------------------------------------------------四、總結
總結來說:
1.iostream處理控制檯IO
2.fstream 處理命名檔案IO
3.stringstream完成記憶體string的IO
後兩者都繼承自iostream,因此很大程度上都能執行一樣的操作。
另外,每個IO物件都還會維護一組條件狀態,用來指出此物件上是否可進行IO操作或者遇到什麼樣的錯誤,標準庫中提供一組函式,可用來設定和檢測這些狀態。