和檔案有關係的輸入輸出類主要在fstream.h這個標頭檔案中被定義,在這個標頭檔案中主要被定義了三個類,由這三個類控制對檔案的各種輸入輸出操作,他們分別是ifstream、ofstream、fstream,其中fstream類是由iostream類派生而來,他們之間的繼承關係見下圖所示。
由於檔案裝置並不像顯示器螢幕與鍵盤那樣是標準預設裝置,所以它在fstream.h標頭檔案中是沒有像cout那樣預先定義的全域性物件,所以我們必須自己定義一個該類的物件,我們要以檔案作為裝置向檔案輸出資訊(也就是向檔案寫資料),那麼就應該使用ofstream類。
ofstream類的預設建構函式原形為:
ofstream::ofstream(const char *filename,int mode = ios::out,int openprot = filebuf::openprot);
filename: 要開啟的檔名
mode: 要開啟檔案的方式
prot: 開啟檔案的屬性
其中mode和openprot這兩個引數的可選項表見下表:
mode屬性表
ios::app: 以追加的方式開啟檔案
ios::ate: 檔案開啟後定位到檔案尾,ios:app就包含有此屬性
ios::binary: 以二進位制方式開啟檔案,預設的方式是文字方式。兩種方式的區別見前文
ios::in: 檔案以輸入方式開啟
ios::out: 檔案以輸出方式開啟
ios::trunc: 如果檔案存在,把檔案長度設為0
可以用“或”把以上屬性連線起來,如ios::out|ios::binary。
openprot屬性表:
0:普通檔案,開啟訪問
1:只讀檔案
2:隱含檔案
4:系統檔案
可以用“或”或者“+”把以上屬性連線起來 ,如3或1|2就是以只讀和隱含屬性開啟檔案。
示例程式碼如下
- #include <fstream>
- using namespace std;
- int main()
- {
- ofstream myfile("c://1.txt",ios::out|ios::trunc,0);
- myfile<<"U love C++"<<endl;
- myfile.close();
- system("pause");
- return 0;
- }
檔案使用完後可以使用close成員函式關閉檔案。
ofstream::app為追加模式,在使用追加模式的時候同時進行檔案狀態的判斷是一個比較好的習慣。 如下面的程式碼:
- #include <iostream>
- #include <fstream>
- using namespace std;
- int main()
- {
- ofstream myfile("e://1.txt",ofstream::app);
- if(myfile.fail())
- {
- cout << "檔案建立失敗!"<<endl;
- exit(-1);
- }
- myfile << " Cobing" <<endl;
- myfile.close();
- system("pause");
- return 0;
- }
在定義ifstream和ofstream類物件的時候,我們也可以不指定檔案。以後可以通過成員函式open()顯式的把一個檔案連線到一個類物件上。如下例:
- #include <iostream>
- #include <fstream>
- using namespace std;
- int main()
- {
- ofstream myfile;
- myfile.open("e://1.txt",ofstream::app);
- if(myfile.fail())
- {
- cout << "檔案建立失敗!"<<endl;
- exit(1);
- }
- myfile << "Cobing" <<endl;
- myfile.close();
- system("pause");
- return 0;
- }
下面我們來看一下是如何利用ifstream類物件,將檔案中的資料讀取出來,然後再輸出到標準裝置中的例子。
- #include <iostream>
- #include <fstream>
- #include <string>
- using namespace std;
- int main()
- {
- ifstream myfile;
- myfile.open("e://1.txt",ifstream::in);
- if(myfile.fail())
- {
- cout << "檔案開啟失敗!"<<endl;
- exit(1);
- }
- char ch;
- string content;
- while(myfile.get(ch))
- {
- content+=ch;
- }
- myfile.close();
- cout << content <<endl;
- system("pause");
- return 0;
- }
我們利用成員函式get(),逐一的讀取檔案中的有效字元,get()成員函式會在檔案讀到默尾的時候返回假值,所以我們可以利用它的這個特性作為while迴圈的終止條件,我們同時也在上例中引入了C++風格的字串型別string,在迴圈讀取的時候逐一儲存到content中。
我們在簡單介紹過ofstream類和ifstream類後,我們再來看一下fstream類,fstream類是由iostream派生而來,fstream類物件可以同對檔案進行讀寫操作。
- #include <iostream>
- #include <fstream>
- using namespace std;
- int main()
- {
- fstream myfile;
- myfile.open("e://1.txt",fstream::out|fstream::app);
- if(myfile.fail())
- {
- cout << "open failed!"<<endl;
- exit(1);
- }
- myfile << "cobing love C++" << endl;
- myfile.close();
- myfile.open("e://1.txt",fstream::in);
- if(myfile.fail())
- {
- cout << "open file failed!"<<endl;
- exit(1);
- }
- char ch;
- while(myfile.get(ch))
- {
- cout << ch;
- }
- myfile.close();
- system("pause");
- return 0;
- }
由於fstream類可以對檔案同時進行讀寫操作,所以對它的物件進行初始話的時候一定要顯式的指定mode和openprot引數。
接下來我們來學習一下串流類的基礎知識,什麼叫串流類?
簡單的理解就是能夠控制字串型別物件進行輸入輸出的類,C++不光可以支援C++風格的字串流控制,還可以支援C風格的字串流控制。
我們先看看看C++是如何對C風格的字串流進行控制的,C中的字串其實也就是字元陣列,字元陣列內的資料在記憶體中的位置的排列是連續的,我們通常用char str[size]或者char *str的方式宣告建立C風格字元陣列,為了能讓字元陣列作為裝置並提供輸入輸出操作,C++引入了ostrstream、istrstream、strstream這三個類,要使用他們建立物件就必須包含strstream.h標頭檔案。
istrstream類用於執行C風格的串流的輸入操作,也就是以字串陣列作為輸入裝置。
ostrstream類用於執行C風格的串流的輸出操作,也就是一字串陣列作為輸出裝置。
strstream類同時可以支援C風格的串流的輸入輸出操作。
istrstream類是從istream(輸入流類)和strstreambase(字串流基類)派生而來,ostrstream是從ostream(輸出流類)和strstreambase(字串流基類)派生而來,strstream則是從iostream(輸入輸出流類)和和strstreambase(字串流基類)派生而來。
串流同樣不是標準裝置,不會有預先定義好的全域性物件,所以不能直接操作,需要通過建構函式建立物件。
類istrstream的建構函式原形如下:
istrstream::istrstream(const char *str,int size);
引數1表示字串陣列,而引數2表示陣列大小,當size為0時,表示istrstream類物件直接連線到由str所指向的記憶體空間並以/0結尾的字串。
- #include <iostream>
- #include <strstream>
- using namespace std;
- int main()
- {
- char *name = "key love c++";
- int arraysize = strlen(name) + 1;
- istrstream istr(name,arraysize);
- char temp='.';
- istr >> temp;
- system("pause");
- return 0;
- }
類ostrstream用於執行C風格的串流的輸出,它的建構函式如下所示:
ostrstream::ostrstream(char *_Ptr,int streamsize,int Mode = ios::out);
第一個引數是字元陣列,第二個是說明陣列的大小,第三個引數是指開啟方式。
接下來我們繼續看一下C++風格的串流控制,C++引入了ostringstream、istringstream、stringstream這三個類,要使用他們建立物件就必須包含sstream.h標頭檔案。
istringstream類用於執行C++風格的串流的輸入操作。
ostringstream類用於執行C++風格的串流的輸出操作。
stringstream類同時可以支援C++風格的串流的輸入輸出操作。
istringstream是由一個string物件構造而來,istringstream類從一個string物件讀取字元。
istringstream的建構函式原形如下:
istringstream::istringstream(string str);
- #include <iostream>
- #include <sstream>
- using namespace std;
- int main()
- {
- istringstream is;
- is.str("k e y 1");
- cout << is.str() <<endl;
- system("pause");
- return 0;
- }
ostringstream的建構函式原形如下:
ostringstream::ostringstream(string str);
- #include <iostream>
- #include <sstream>
- #include <string>
- using namespace std;
- int main()
- {
- ostringstream os;
- os.put('a');
- os.put('b');
- os << "ccde";
- string str = os.str();
- cout << str << endl;
- system("pause");
- return 0;
- }
上例在控制檯輸出"abccde";
我們通過put()或者左移操作符可以不斷向ostr插入單個字元或者是字串,通過str()函式返回增長過後的完整字串資料,但值得注意的一點是,當構造的時候物件內已經存在字串資料的時候,那麼增長操作的時候不會從結尾開始增加,而是修改原有資料,超出的部分增長。
stringstream的建構函式原形如下:
stringstream::stringstream(string str);
stringstream類的物件我們還常用它進行string與各種內建型別資料之間的轉換。
- #include <iostream>
- #include <sstream>
- #include <string>
- using namespace std;
- int main()
- {
- stringstream format_message;
- int val1=512, val2=1024;
- string init_str="/nwell done";
- format_message << "val1:" << val1 << "/n"
- << "val2:" << val2;
- format_message << init_str;
- string get_message=format_message.str();
- cout << get_message << endl;
- system("pause");
- return 0;
- }
上例輸出:
val1:512
val2: 1024
well done
接下來我們來學習一下輸入/輸出的狀態標誌的相關知識,C++中負責的輸入/輸出的系統包括了關於每一個輸入/輸出操作的結果的記錄資訊。這些當前的狀態資訊被包含在io_state型別的物件中。io_state是一個列舉型別(就像open_mode一樣),以下便是它包含的值。
goodbit 無錯誤
eofbit 已到達檔案尾
failbit 非致命的輸入/輸出錯誤,可挽回
badbit 致命的輸入/輸出錯誤,無法挽回
有兩種方法可以獲得輸入/輸出的狀態資訊。一種方法是通過呼叫rdstate()函式,它將返回當前狀態的錯誤標記。例如,假如沒有任何錯誤,則rdstate()會返回goodbit.
- #include <iostream>
- using namespace std;
- int main()
- {
- int a;
- cin >> a;
- cout << cin.rdstate() << endl;
- if(cin.rdstate()== istream::goodbit)
- {
- cout << "correct!";
- }
- if(cin.rdstate() == istream::failbit)
- {
- cout << "failed!";
- }
- system("pause");
- return 0;
- }
上例輸出:0 correct!
另一種方法則是使用下面任何一個函式來檢測相應的輸入/輸出狀態:
bool bad();
bool eof();
bool fail();
bool good();
- #include <iostream>
- using namespace std;
- int main()
- {
- int a;
- cin >> a;
- cout << cin.rdstate() << endl;
- if(cin.good())
- {
- cout << "correct!";
- }
- if(cin.fail())
- {
- cout << "failed!";
- }
- system("pause");
- return 0;
- }
如果錯誤發生,那麼流狀態既被標記為錯誤,你必須清除這些錯誤狀態,以使你的程式能正確適當地繼續執行。要清除錯誤狀態,需使用clear()函式。此函式帶一個引數,它是你將要設為當前狀態的標誌值。,只要將stream::goodbit作為實參。
- #include <iostream>
- #include <string>
- using namespace std;
- int main()
- {
- int a;
- cin >> a;
- cout << cin.rdstate() << endl;
- cin.setstate(iostream::failbit);
- cout << cin.rdstate() << endl;
- system("pause");
- return 0;
- }
輸出:0 2 (其中goodbit為0,failbit為2)。
本文參考:
//管寧
//www.cndev-lab.com