C++:IO類,文件輸入輸出,string流練習題
前面已經在用的IO庫設施
- istream:輸入流類型,提供輸入操作。
- ostream:輸出流類型,提供輸出操作
- cin:一個istream對象,從標準輸入讀取數據。
- cout:一個ostream對象,向標準輸出寫入數據。
- cerr:一個ostream對象,向標準錯誤寫入消息。
- >>運算符:用來從一個istream對象中讀取輸入數據。
- <<運算符:用來向一個ostream對象中寫入輸出數據。
- getline函數:從一個給定的istream對象中讀取一行數據,存入到一個給定的string對象中。
IO類
iostream
頭文件:從標準流中讀寫數據,istream
,ostream
等fstream
頭文件:從文件中讀寫數據,ifstream
,ofstream
等sstream
頭文件:從字符串中讀寫數據,istringstream
,ostringstream
IO對象不能拷貝或賦值
由於不能拷貝IO對象,因此不能將 形參 或 返回類型 設置為 流類型。進行 IO 操作的函數通常以 引用方式 傳遞和 返回流。讀寫一個IO對象會改變其狀態,因此 傳遞和返回的引用不能用const。
- IO對象不能存在容器裡.
- 形參和返回類型也不能是流類型。
- 形參和返回類型一般是流的引用。
- 讀寫一個IO對象會改變其狀態,因此傳遞和返回的引用不能是const的。
條件狀態
狀態 | 解釋 |
---|---|
strm:iostate | 是一種機器無關的類型,提供瞭表達條件狀態的完整功能 |
strm:badbit | 用來指出流已經崩潰 |
strm:failbit | 用來指出一個IO操作失敗瞭 |
strm:eofbit | 用來指出流到達瞭文件結束 |
strm:goodbit | 用來指出流未處於錯誤狀態,此值保證為零 |
s.eof() | 若流s的eofbit置位,則返回true |
s.fail() | 若流s的failbit置位,則返回true |
s.bad() | 若流s的badbit置位,則返回true |
s.good() | 若流s處於有效狀態,則返回true |
s.clear() | 將流s中所有條件狀態位復位,將流的狀態設置成有效,返回void |
s.clear(flags) | 將流s中指定的條件狀態位復位,返回void |
s.setstate(flags) | 根據給定的標志位,將流s中對應的條件狀態位置位,返回void |
s.rdstate() | 返回流s的當前條件狀態,返回值類型為strm::iostate |
上表中,strm是一種IO類型,(如istream), s是一個流對象。
管理輸出緩沖
- 每個輸出流都管理一個緩沖區,用來保存程序讀寫的數據。文本串可能立即打印出來,也可能被操作系統保存在緩沖區內,隨後再打印。
- 刷新(即,數據真正寫到輸出設備或文件)緩沖區的IO操縱符
endl
:輸出一個換行符並刷新緩沖區flush
:刷新流,但不添加任何字符ends
:在緩沖區插入空字符null,然後刷新unitbuf
:告訴流接下來每次操作之後都要進行一次flush操作。nounitbuf
:回到正常的緩沖方式
文件輸入輸出
頭文件fstream定義瞭三個類型來支持文件IO:
ifstream
從一個給定文件讀取數據。ofstream
向一個給定文件寫入數據。fstream
可以讀寫給定文件。
fstream特有的操作
操作 | 解釋 |
---|---|
fstream fstrm; | 創建一個未綁定的文件流。 |
fstream fstrm(s); | 創建一個文件流,並打開名為s的文件,s可以是string也可以是char指針 |
fstream fstrm(s, mode); | 與前一個構造函數類似,但按指定mode打開文件 |
fstrm.open(s) | 打開名為s的文件,並和fstrm綁定 |
fstrm.close() | 關閉和fstrm綁定的文件 |
fstrm.is_open() | 返回一個bool值,指出與fstrm關聯的文件是否成功打開且尚未關閉 |
上表中,fstream
是頭文件fstream
中定義的一個類型,fstrm是一個文件流對象。
文件模式
文件模式 | 解釋 |
---|---|
in | 以讀的方式打開 |
out | 以寫的方式打開 |
app | 每次寫操作前均定位到文件末尾 |
ate | 打開文件後立即定位到文件末尾 |
trunc | 截斷文件 |
binary | 以二進制方式進行IO操作。 |
string流
頭文件sstream
定義瞭三個類型來支持內存IO:
istringstream
從string讀取數據。ostringstream
向string寫入數據。stringstream
可以讀寫給定string。
stringstream特有的操作
操作 | 解釋 |
---|---|
sstream strm | 定義一個未綁定的stringstream對象 |
sstream strm(s) | 用s初始化對象 |
strm.str() | 返回strm所保存的string的拷貝 |
strm.str(s) | 將s拷貝到strm中,返回void |
上表中sstream
是頭文件sstream
中任意一個類型。s是一個string。
書中演示demo使用
#include <iostream> #include <string> #include <vector> #include <sstream> using namespace std; typedef struct PersonInfo { string name; vector<string> phones; }p; int main() { string line, word; vector<p> people; while (getline(cin, line)) { p info; istringstream record(line); record >> info.name; while (record >> word) info.phones.push_back(word); people.push_back(info); } for (auto i : people) { cout << i.name << endl; for (auto j : i.phones) cout << j << " "; cout << endl; } return 0; }
練習
練習1
編寫函數,接受一個istream&參數,返回值類型也是istream&。此函數須從給定流中讀取數據,直至遇到文件結束標識時停止。它將讀取的數據打印在標準輸出上。完成這些操作後,在返回流之前,對流進行復位,使其處於有效狀態。
解:
std::istream& func(std::istream &is) { std::string buf; while (is >> buf) std::cout << buf << std::endl; is.clear(); return is; }
練習2
測試函數,調用參數為cin。
解:
#include <iostream> using std::istream; istream& func(istream &is) { std::string buf; while (is >> buf) std::cout << buf << std::endl; is.clear(); return is; } int main() { istream& is = func(std::cin); std::cout << is.rdstate() << std::endl; return 0; }
測試
#include <iostream> #include <string> using namespace std; istream& f1(istream& is) { int s; while (is >> s) { cout << s << endl; } return is; } istream& f2(istream& is) { int s; while (is >> s) { cout << s << endl; } is.clear(); return is; } int main() { istream& is = f1(cin); cout << is.rdstate() << endl; istream& is2 = f2(cin); cout << is2.rdstate() << endl; return 0; }
練習3
什麼情況下,下面的while循環會終止?
while (cin >> i) /* ... */
如badbit、failbit、eofbit 的任一個被置位,那麼檢測流狀態的條件會失敗。
練習4
編寫函數,以讀模式打開一個文件,將其內容讀入到一個string的vector中,將每一行作為一個獨立的元素存於vector中。
#include <iostream> #include <string> #include <vector> #include <fstream> using namespace std; void ReadFileToVec(const string& filename, vector<string>& vec) { ifstream ifs(filename); if (ifs) { string buf; while (getline(ifs, buf)) vec.push_back(buf); } }
練習5
重寫上面的程序,將每個單詞作為一個獨立的元素進行存儲。
void ReadFileToVec(const string& fileName, vector<string>& vec) { ifstream ifs(fileName); if (ifs) { string buf; while (ifs >> buf) vec.push_back(buf); } }
練習6
編寫程序,將來自一個文件中的行保存在一個vector中。然後使用一個istringstream從vector讀取數據元素,每次讀取一個單詞。
#include <iostream> #include <string> #include <sstream> #include <fstream> #include <vector> using namespace std; int main() { //將來自一個文件的行保存到vector中 ifstream ifs("hello.txt"); if (!ifs) { cerr << "no data ?" << endl; return -1; } vector<string> vecline; string line; while(getline(ifs, line)) vecline.push_back(line); ifs.close(); //從vector讀取元素,每次隻讀一個單詞 for (auto &s : vecline) { istringstream iss(s); string word; while (iss >> word) cout << word << endl; } return 0; }
練習7
本節的程序在外層while循環中定義瞭istringstream對象。如果record對象定義在循環之外,你需要對程序進行怎樣的修改?重寫程序,將record的定義移到while循環之外,驗證你設想的修改方法是否正確。
解:
#include <iostream> #include <sstream> #include <string> #include <vector> using std::vector; using std::string; using std::cin; using std::istringstream; struct PersonInfo { string name; vector<string> phones; }; int main() { string line, word; vector<PersonInfo> people; istringstream record; while (getline(cin, line)) { PersonInfo info; record.clear(); record.str(line); record >> info.name; while (record >> word) info.phones.push_back(word); people.push_back(info); } for (auto &p : people) { std::cout << p.name << " "; for (auto &s : p.phones) std::cout << s << " "; std::cout << std::endl; } return 0; }
練習8
我們為什麼沒有在PersonInfo中使用類內初始化?
解:
因為這裡隻需要聚合類就夠瞭,所以沒有必要在PersionInfo中使用類內初始化。
練習9
電話號碼程序
#include <iostream> #include <string> #include <sstream> #include <fstream> #include <vector> using namespace std; struct PersonInfo { string name; vector<string> phones; }; bool valid(const string& str) { return isdigit(str[0]); } string format(const string& str) { return str.substr(0, 3) + "-" + str.substr(3, 3) + "-" + str.substr(6); } int main() { //從文件中讀取信息存入vector容器 ifstream ifs("phone.txt"); if (!ifs) { cerr << "no phone numbers ? " << endl; return -1; } vector<PersonInfo> people; string line, word; istringstream record; while (getline(ifs, line)) { PersonInfo info; record.clear(); record.str(line); record >> info.name; while (record >> word) { info.phones.push_back(word); } people.push_back(info); } //逐個驗證電話號碼 並 改變其格式 for (const auto& entry : people) //對people中的每一項 { //每個循環創建的對象 ostringstream formatted, badnums; //對每個數 for (const auto& nums : entry.phones) { if (!valid(nums)) { badnums << " " << nums; //將數的字符串形式存入badnums } else { //將格式化的字符串寫入formatted formatted << " " << format(nums); } } //沒有錯誤的數 if (badnums.str().empty()) { cout << entry.name << " " << formatted.str() << endl; } else { //打印名字和錯誤的數 cerr << "input error: " << entry.name << " invalid number(s)" << badnums.str() << endl; } } return 0; }
總結
本篇文章就到這裡瞭,希望能夠給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容!