第八﹑九章 I/O系統 檔案I/O的基本概念 格式化I/O 建立自訂的嵌入子 建立自訂的擷取子 自訂I/O與檔案
檔案I/O的基本概念 C++對I/O的支援是放在<iostream>中, 而Class ios包括有許多成員函數與變數可以用來控制和監督串流的運作. 要處理檔案I/O,心必須#include<fstream>,它包含了ifstream,ofstream and fstream,而這些class是衍生自istream,ostream而此兩個class是衍生自ios
檔案I/O的基本概念 在C++中,開啟一個File就是鏈結到一個stream;而stream有三種型態: ifstream in; // input ofstream out; // output fstream io; // input and output 一旦建立stream後,利用open()便可以將stream與file 鏈結在一起.
OPEN()函數 void ifstream::open(const char *filename,openmode mode=ios::in); void ofstream::open(const char *filename,openmode mode=ios::in | ios::trunc); void fstream::open(const char *filename,openmode mode=ios::in |ios::out);
Openmode ios::app //所有的輸出附加到檔案結尾 ios::ate //將檔案指標移到檔案結尾 ios::binary //以二進位模式開啟檔案 ios::in //開啟檔案作為輸入使用 ios::out //開啟檔案作為輸出使用 ios::trunc //會覆寫之前同名的檔案
使用Open函數開啟檔案 Ofstream mystream; Mystream.open(“test”); 判斷開啟與否 If(!mystream){cout<<“cannot open file\n”;} 或可利用is_open()判斷開啟與否 Bool is_open();如果開啟file則傳回true;否則則傳回false; If(!mystream.is_open()){{cout<<“cannot open file\n”;}
Stream的建構函數 儘管可以使用open()開檔,但更方便的方法則是使用 ifstream mystream(“myfile”);//open file 因為在ifstream,ofstream,fstream中的建構函數會自動開啟檔案. 判斷是否到檔案結尾則是用bool eof(); 關閉檔案則是用close();
檔案內容的讀寫 當file己開啟時,不在使用cin與cout來讀寫檔案,而是改成“>>”與“<<”,就像是c中的fprintf()與fscan().
開關檔範例1 #include<iostream> #include<fstream> using namespace std; int main() { ofstream fout("c:\\test.dat"); if(!fout){ cout<<"cannot open file\n";return 1; } fout<<"Hello\n"; fout<<100<<' '<<hex<<100<<endl; fout.close(); ifstream fin("c:\\test.dat"); if(!fin){ cout<<"cannot open file\n";return 1; } char str[80]; int i; fin>>str>>i; cout<<str<<' '<<i<<endl; fin.close(); return 0;}
課後練習 寫一程式來計算檔案中的字元個數.
格式化的I/O 在每個stream中都有一格式化flag的集合,可以用來控制資料的格式;在class ios中就宣告了一列舉型別fmtflags它定義了 skipws //忽略空白字元 left //輸出向左靠攏 oct //八進位輸出表示 hex //十六進位輸出表示 uppercase //字元輸出變大寫
格式化的I/O showpos //顯示正數前加‘+’符號 showpoint //在float時顯示小數點和其 後的零 scientific //以科學符號顯示 fixed //以一般方式顯示 要設定一格式旗標使用ios的成員函數 setf() // fmtflags setf(fmtflags flags) ex: stream.setf(ios::showpos);
格式化的I/O 而unseft()函數可用來清除flag設定值 void unseft(fmtflags flags); 要了解目前flag的設定則使用flag()函數 fmtflags flag(); fmtflags flag(fmtflags f);
設定多種旗標格式範例 #include<iostream> using namespace std; int main(){ // show using default setting cout<<123.23<<"hello“ <<100<<'\n'; cout<<10<<' '<<-10<<'\n'; cout<<100.0<<"\n\n"; //now, change formats cout.unsetf(ios::dec); cout.setf(ios::hex|ios::scientific); cout<<123.23 <<"hello" <<100<<'\n'; cout.setf(ios::showpos); cout<<10<<' '<<-10<<'\n'; cout.setf(ios::showpoint|ios::fixed); cout<<100.0<<"\n\n"; return 0; }
改變大小寫範例 #include<iostream> using namespace std; int main(){ cout.unsetf(ios::dec); cout.setf(ios::uppercase|ios::showbase|ios::hex); cout<<88<<"\n\n"; cout.unsetf(ios::uppercase); return 0; }
練習 寫一程式來設定cout flag.在show float 時可以show出小數點;另外以科學技號再加上大寫E來show出所有的float.
建立自訂的嵌入子 在C++中,輸出的動作被叫作嵌入,而“<<”則被稱為嵌入運算子(insertion operator) ostream& operator<<(ostream& out, class-name ob) { // body or inserter return stream;}
建立自訂的嵌入子 第一個參數是對ostream的參考型態,這代表stream必須要是一個output stream 第二個參數則代表要輸出的物件(也可以是一參考參數) 嵌入函數傳回stream的參考,這是為了讓“<<”能在一連串的I/O運算中使用 Ex:cout<<ob1<<ob2<<ob3;
建立自訂的嵌入子 由於嵌入子左運算元是一stream;而右運算元是要輸出的物件,如果將嵌入子函數放進class變成成員函數,它的左運算元會自動由this指標被設為產生這個呼叫的物件.因此嵌入子不能放入class中. 為了讓嵌入子函數可存取class中的成員則嵌入子要變為該class中的friend.
嵌入子範例-成為friend #include<iostream> using namespace std; class coord{ int x,y; public: coord(){x=0;y=0;} coord(int a,int b){x=a;y=b;} friend ostream &operator<<(ostream &stream,const coord& ob); };
嵌入子範例-成為friend ostream &operator<<(ostream &stream, const coord& ob) {stream<<ob.x<<" , "<<ob.y<<'\n'; return stream;} int main() { coord a(1,1),b(2,3); cout<< a<< b; return 0;}
嵌入子範例-不成為friend #include<iostream> using namespace std; class coord{ public: int x,y; coord(){x=0;y=0;} coord(int a,int b){x=a;y=b;} // friend ostream &operator<<(ostream &stream, const coord ob); };
嵌入子範例-不成為friend ostream &operator<<(ostream &stream,const coord ob) { stream<<ob.x<<" , "<<ob.y<<'\n'; return stream;} int main() { coord a(1,1),b(2,3); cout<<a<<b; return 0; }
建立自訂的擷取子 在C++中,輸入的動作被叫作擷取運算子(extraction operator), istream& operator>>(istream& stream, class-name ob) { // body or inserter return stream;}
擷取子範例 #include<iostream.h> //using namespace std; class coord{ int x,y; public: coord(){x=0;y=0;} coord(int a,int b){x=a;y=b;} friend istream &operator>>(istream &stream,coord& ob); friend ostream &operator<<(ostream &stream,coord& ob); };
擷取子範例 istream &operator>>(istream &stream, coord& ob) { cout<<"Enter coordinates\n"; stream>>ob.x>>ob.y; return stream; } ostream &operator<<(ostream &stream, coord& ob) stream<<ob.x<<" , "<<ob.y<<'\n';
擷取子範例 int main() { coord a(1,1),b(2,3); cout<<a<<b; cin>>a; cout<<a; return 0; }
自訂I/O與檔案 結合開檔與“>>”和“<<”兩個運算子 #include<iostream> #include<fstream> using namespace std; class coord{ int x,y; public: coord(){x=0;y=0;} coord(int a,int b){x=a;y=b;} friend ostream &operator<<(ostream &stream, coord &ob); friend istream &operator>>(istream &stream,coord &ob); };
自訂I/O與檔案 ostream &operator<<(ostream &stream,coord& ob) { stream<<ob.x <<'\n'; stream<<ob.y<<'\n'; return stream;} istream &operator>>(istream &stream,coord &ob) { stream>>ob.x>>ob.y; int main() {
自訂I/O與檔案 coord a(1,1),b(2,3); ofstream out("c:\\test.dat"); if(!out){cout<<"cannot open output file\n"; return 1; } out<<a<<b; out.close(); ifstream in("c:\\test.dat"); if(!in){cout<<"cannot open input file\n"; return 1;}
自訂I/O與檔案 coord c(0,0),d(0,0); in>>c>>d; cout<<c<<d; in.close(); return 0; }
練習 請撰寫一class,它可以儲存一整數值和它最小的因數(factor),請加入嵌入子與擷取子.