- iostream定義了用於讀寫流的基本類型,fstream定義了讀寫命名文件的類型,sstream定義了讀寫內存string對象的類型。
- 標準庫使咱們能忽略這些不一樣類型的流之間的差別,這是經過繼承機制實現的。
- 因爲不能拷貝IO對象,所以咱們也不能將形參或返回類型設置爲流類型。進行IO操做的函數一般以引用方式傳遞和返回流。讀寫一個IO對象會改變其狀態,所以傳遞和返回的引用不能是const的
- IO庫條件狀態
狀態 |
解釋 |
strm::iostate |
strm是一種IO類型,iostate是一種機器相關的類型,提供了表達條件狀態的完整功能。IO庫定義了4個iostate類型的constexpr值,表示特定的位模式。 |
strm::badbit |
二進制值爲100,用來指出流已崩潰 |
strm::failbit |
二進制值爲010,用來指出一個IO操做失敗了 |
strm::eofbit |
二進制值爲001,用來指出流已到達了文件結束 |
strm::goodbit |
用來指出流未處於錯誤狀態。此值保證爲零 |
s.eof() |
若流s的eofbit置位(置1),則返回true |
s.fail() |
若流s的failbit或badbit置位,則返回true |
s.bad() |
若流s的badbit置位,則返回true |
s.good() |
若流s處於有效狀態,則返回true |
s.clear() |
將流s中全部條件狀態位復位(置0),將流的狀態設置爲有效。返回void |
s.clear(flags) |
根據給定的flags標誌位,將流s中對應條件狀態位置位。flags的類型爲strm::iostate。返回void |
s.setstate(flags) |
根據給定的flags標誌位,將流s中對應條件狀態位置位。flags的類型爲strm::iostate。返回void |
s.rdstate() |
返回流s的當前條件狀態,返回值類型爲strm::iostate |
#include<iostream>
#include<string>
using namespace std;
istream& func(istream& is)
{
int v;
while (is >> v, !is.eof()) // 直到遇到文件結束符才中止讀取
{
if (is.bad())
{
cerr << "Bad Error!\n";
break;
}
else if (is.fail())
{
cerr << "Wrong Data! Please try again!\n";
is.clear();
is.ignore(1024, '\n');
continue;
}
cout << v << endl;
}
is.clear();
return is;
}
int main()
{
func(cin);
return 0;
}
- badbit表示系統級錯誤,如不可恢復的讀寫錯誤。一般狀況下,一旦badbit被置位,流就沒法再使用了。在發生可恢復錯誤後,failbit被置位,如指望讀取數值卻讀出一個字符等錯誤。這種問題一般是能夠修正的,流還能夠繼續使用。若是到達文件結束位置,eofbit和failbit都會被置位。goodbit的值爲0,表示流未發生錯誤。若是badbit、failbit和eofbit任一個被置位,則檢測流狀態的條件會失敗。
- 在badbit被置位時,fail也會返回true。這意味着,使用good或fail是肯定流的整體狀態的正確方法。實際上,咱們將流看成條件使用的代碼就等價於
!fail()
。而eof和bad操做只能表示特定的錯誤。
- 下面的代碼將
failbit
和badbit
復位,但保持eofbit
不變:// 復位failbit和badbit,保持其餘標誌位不變
cin.clear(cin.rdstate() & ~cin.failbit & ~cin.badbit);
/*
* clear和setstate的區別:
* clear用實參值強制覆蓋當前流的條件狀態(不管是0仍是1)
* setstate將實參值(置1的位)疊加到當前流的條件狀態
*/
- 致使緩衝刷新的緣由:
- 程序正常結束,做爲main函數的return操做的一部分,緩衝刷新被執行。
- 緩衝區滿時,須要刷新緩衝,然後新的數據才能繼續寫入緩衝區。
- 咱們可使用操縱符endl來顯式刷新緩衝區
- 在每一個輸出操做以後,咱們能夠用操縱符unitbuf設置流的內部狀態,來清空緩衝區。默認狀況下,對cerr是設置unitbuf的,所以寫到cerr的內容都是當即刷新的。
- 一個輸出流可能被關聯到另外一個流。在這種狀況下,當讀寫被關聯的流時,關聯到的流的緩衝區會被刷新。例如,默認狀況下,cin和cerr都關聯到cout,所以,讀cin或寫cerr都會致使cout的緩衝區被刷新。
- 操縱符endl完成換行並刷新緩衝區的工做。flush刷新緩衝區,但不輸出任何額外的字符。ends向緩衝區插入一個空字符(
'\0'
),而後刷新緩衝區。
- 若是想在每次輸出操做後都刷新緩衝區,咱們可使用unitbuf操縱符。它告訴流在接下來的每次寫操做以後都進行一次flush操做。而nounitbuf操縱符則重置流,使其恢復使用正常的系統管理的緩衝區刷新機制:
cout << unitbuf; // 全部輸出操做後都會當即刷新緩衝區
// 任何輸出都當即刷新,無緩衝
cout << nounitbuf; // 回到正常的緩衝方式
- 若是程序異常終止,輸出緩衝區是不會被刷新的。當一個程序崩潰後,它所輸出的數據極可能停留在輸出緩衝區中等待打印。
- 當一個輸入流被關聯到一個輸出流時,任何試圖從輸入流讀取數據的操做都會先刷新關聯的輸出流。
- 交互式系統一般應該關聯輸入流和輸出流。這意味着全部輸出,包括用戶提示信息,都會在讀操做以前被打印出來。
- tie有兩個重載的版本:一個版本不帶參數,返回指向輸出流的指針。若是本對象當前關聯到一個輸出流,則返回的就是指向這個流的指針,若是對象未關聯到流,則返回空指針。tie的第二個版本接受一個指向ostream的指針,將本身關連到此ostream,並返回上一個綁定的輸出流指針。
- 咱們既能夠將一個istream對象關聯到另外一個ostream,也能夠將一個ostream關聯到另外一個ostream。每一個流同時最多關聯到一個流,但多個流能夠同時關聯到同一個ostream
cin.tie(&cout); // 僅僅是用來展現:標準庫將cin和cout關聯在一塊兒
// old_tie指向當前關聯到cin的流(若是有的話)
ostream *old_tie = cin.tie(nullptr); // cin再也不與其餘流關聯
// 將cin與cerr關聯;這不是一個好主意,由於cin應該關聯到cout
cin.tie(&cerr); // 讀取cin會刷新cerr而不是cout
cin.tie(old_tie); // 重建cin和cout間的正常關聯
- fstream特有的操做
操做 |
解釋 |
fstream fstrm; |
建立一個未綁定的文件流。fstream是頭文件fstream中定義的一個類型 |
fstream fstrm(s); |
建立一個fstream,並打開名爲s的文件。s能夠是string類型,或者是一個指向C風格字符串的指針。這些構造函數都是explicit的。默認的文件模式mode依賴於fstream的類型。 |
fstream fstrm(s, mode); |
與前一個構造函數相似,但按指定mode打開文件 |
fstrm.open(s) |
打開名爲s的文件,並將文件與fstrm綁定。s能夠是一個string或一個指向C風格字符串的指針。默認的文件mode依賴於fstream的類型。返回void |
fstrm.close() |
關閉與fstrm綁定的文件。返回void |
fstrm.is_open() |
返回一個bool值,指出與fstrm關聯的文件是否成功打開且還沒有關閉 |
- 在要求使用基類型對象的地方,咱們能夠用繼承類型的對象來替代。這意味着,接受一個iostream類型引用(或指針)參數的函數,能夠用一個對應的fstream(或sstream)類型來調用。
- 若是調用open失敗,failbit會被置位。由於調用open可能失敗,進行open是否成功的檢測一般是一個好習慣。
if (out) // 檢查open是否成功
// open成功,咱們可使用文件了
- 一旦一個文件流已經打開,它就保持與對應文件的關聯。爲了將文件流關聯到另一個文件,必須首先關閉已經關聯的文件。一旦文件成功關閉,咱們能夠打開新的文件。
in.close() // 關閉文件
in.open(ifile + "2"); // 打開另外一個文件
- 當一個fstream對象被銷燬時,close會自動被調用。
- 每一個流都有一個關聯的文件模式,用來指出如何使用文件。
模式 |
解釋 |
in |
以讀方式打開 |
out |
以寫方式打開 |
app |
每次寫操做前均定位到文件末尾 |
ate |
打開文件後當即定位到文件末尾 |
trunc |
截斷文件 |
binary |
以二進制方式進行IO |
- 指定文件模式有以下限制:
- 只能夠對ofstream或fstream對象設定out模式
- 只能夠對ifstream或fstream對象設定in模式
- 只有當out也被設定時纔可設定trunc模式
- 只要trunc沒被設定,就能夠設定app模式。在app模式下,即便沒有顯式指定out模式,文件也老是以輸出方式被打開
- 默認狀況下,即便咱們沒有指定trunc,以out模式打開的文件也會被截斷。爲了保留以out模式打開的文件的內容,咱們必須同時指定app模式,這樣只會將數據追加寫到文件末尾;或者同時指定in模式,即打開文件同時進行讀寫操做。
- ate和binary模式可用於任何類型的文件流對象,且能夠與其餘任何文件模式組合使用。
- 保留被ofstream打開的文件中已有數據的惟一方法是顯式指定app或in模式
- 在每次打開文件時,都要設置文件模式,多是顯式地設置,也多是隱式地設置。當程序未指定模式時,就使用默認值。
- stringstream特有的操做
操做 |
解釋 |
sstream strm; |
strm是一個未綁定地stringstream對象。sstream是頭文件sstream中定義的一個類型 |
sstream strm(s); |
strm是一個sstream對象,保存string s的一個拷貝。此構造函數是explicit的 |
strm.str() |
返回strm所保存的string的拷貝 |
strm.str(s) |
將string s拷貝到strm中。返回void |
#include<iostream>
#include<sstream>
#include<string>
#include<vector>
using namespace std;
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(); // 重複使用字符串流時,每次都要調用clear
record.str(line); // 將記錄綁定到剛讀入的行
record >> info.name; // 讀取名字
while (record >> word) // 讀取電話號碼
info.phones.push_back(word); // 保持它們
people.push_back(info); // 將此記錄追加到people末尾
}
return 0;
}