Streams and File I/O Cheng-Chin Chiang
Streams 串流是 C++ 中一種負責資料輸出入程式的機制 輸入串流 : 資料流入程式 鍵盤 程式 檔案 程式 輸出串流 : 資料流出程式 程式 螢幕 程式 檔案
String Usage 我們已經學過的串流 cn: 鍵盤輸入串流 cout:: 螢幕輸出串流 我們可以定義其他形式的串流 例如 : 檔案輸入或檔案輸出 使用方法與 cin,cout 相當類似 例如 int Num; instream >> Num; int Num1, Num2; outstream << Num1<<Num2;
File Streams 以檔案作為資料輸出入串流 須先與檔案連結 指定輸出或輸入模式 輸入 :ifstream 物件 輸出 :ofstream 物件 開檔 : 指定檔案 使用前請先 #include <fstream> 標頭檔 請 using namespace std; #include <fstream> using namespace std; 關檔 或 #include <fstream> using std::ifstream; using std::ofstream;
Using File Streams 宣告串流物件 ifstream instream; ofstream outstream; 開檔 instream.open("infile.txt"); outstream.open( outfile.txt ); I/O 關檔 instream >> onenumber >> anothernumber; outstream << "onenumber = " << onenumber << " anothernumber = " << anothernumber; instream.close(); outstream.close();
Using File Streams 宣告串流物件 ifstream instream; ofstream outstream; 開檔 instream.open("infile.txt"); outstream.open( outfile.txt ); I/O 關檔 instream >> onenumber >> anothernumber; outstream << "onenumber = " << onenumber << " anothernumber = " << anothernumber; instream.close(); outstream.close();
File Names in open() open() 函數的引數型態為 string 傳入的實際參數可以為常值字串或字串變數 char filename[16]; ifstream instream; cout << "Enter file name: "; cin >> filename; instream.open(filename);
例題 : 檔案輸入與檔案輸出
例題 : 檔案輸入與檔案輸出 ( 續 )
File Output Buffer 檔案的存取速度比記憶體慢很多 程式的輸出必須予以緩衝, 否則檔案可能會來不及接受寫入的資料 程式輸出到檔案前的緩衝機制 檔案 記憶體緩衝區 程式輸出 緩衝區資料送到檔案的時機 緩衝區已滿 指令強迫送出 endl flush() 關檔 (close()) 程式正常結束
Appending to a File 以輸出串流開檔時的一般效果 若打開不存在的檔案 建立新檔, 並準備從檔案開頭開始寫入資料 若打開已存在的檔案 原資料檔內的資料全部清空 以輸出串流做附加資料 (append data) 的開檔 ofstream outstream; outstream.open("important.txt", ); 若打開不存在的檔案 建立新檔, 自開頭寫入 若打開已存在的檔案 自檔尾開始寫入 類別 ios 定義於 <iostream> 和 std namespace
Modes for File Open ios:: 開啟模式說明 ios::app ios::ate ios::binary ios::in ios::out ios::trunc 開啟附加模式的資料檔 開啟資料檔並將指標移到檔案結束位置 開啟二進位輸入輸出模式的資料檔開啟輸入模式的資料檔開啟輸出模式的資料檔刪除已經存在的檔案, 再開啟資料檔
例題 :ios::app 和 ios:ate 的差別 void fn1(int i) { ofstream out("out1.txt",ios::ate); out << i << endl; } void fn2(int i) { ofstream out("out2.txt",ios::app); out << i << endl; } main() 中 : for(int i = 0; i < 10; i++) { fn1(i); fn2(i); } out1.txt 中得到的是 : 9 out2.txt 中得到的是 : 0 1 2 3 4 5 6 7 8 9
Another Convenient Way to Open Files 宣告串流物件和開檔一次完成 ifstream instream; ofstream outstream instream.open( infile.txt ); outstream.open( outfile.txt,ios::app); 等同於 ifstream instream("infile.txt"); ofstream outstream( outfile.txt,ios::app);
Checking File Open Success 開檔失敗的可能狀況 檔案不存在 沒有檔案存取權限 不可預期的因素 檢查是否成功開檔的方法 使用串流成員函數 fail() instream.open("stuff.txt"); if (instream.fail()) { cout << "File open failed.\n"; exit(1); }
Character I/O with Files 與 cin 和 cout 的字元輸出入相同 常用的成員函數 ( 屬於 istream 和 ostream 類別 ) get, getline put, putback, peek, ignore
Checking End of File 通常使用於全檔案讀取和處理時 方法一 使用成員函數 eof() instream.get(next); while (!instream.eof()) { cout << next; instream.get(next); }
Checking End of File 方法二 使用 read operation double next, sum = 0; while ( ) sum = sum + next; cout << "the sum is " << sum << endl;
Formatting Output with Stream Functions 與 cout 的格式化輸出相同 輸出串流擁有和 cout 相同的格式化輸出之成員函數 例如 : cout.setf(ios::fixed); cout.setf(ios::showpoint); cout.precision(2); // 設定輸出旗標 // 設定輸出旗標 // 設定有效數字 這幾行可以設定輸出如 12.52, 2.56, 123.14 之格式 一次設定多個旗標 : outstream.setf(ios::fixed ios::showpoint ios::right);
Flags( 旗標 ) 設定不同的輸出格式 C++ 定義許多輸出旗標在 <iostream> 標頭檔 要設定旗標須使用 setf() 成員函數 set in both fmtfl and mask, and clears the format flags whose bits are set in mask but not in fmtfl
例題 : 輸出格式設定 int main () { cout.setf (ios::hex, ios::basefield ); cout << 100 << endl; cout.setf (ios::oct, ios::basefield ); cout << 100 << endl; return 0; } // set hex as the basefield // set hex as the basefield 輸出 : 64 144
More Output Member Functions width() 成員函數 設定下一個輸出值的輸出寬度 例如 :outstream.width(5); int main () { cout << 100 << endl; cout.width(10); cout << 100 << endl; cout.fill('x'); cout.width(15); cout << left << 100 << endl; return 0; }
Manipulators 設定格式化輸出的一些特殊函數, 不是串流類別的成員函數 這些函數的相關定義在 <iomanip> 標頭檔及 std namespace 通常呼叫於 insertion operator (<<) 之後
Manipulator Example: setw() 設定輸出寬度 cout << "Start" << setw(4) << 10 << setw(4) << 20 << setw(6) << 30; 結果 : Start 10 20 30 每個 setw() 只套用在追隨在後的那一筆輸出資料
Manipulator setprecision() 設定有效小數數字 cout.setf(ios::fixed ios::showpoint); cout << "$" << setprecision(2) << 10.3 << " " << "$" << 20.5 << endl; 結果 : $10.30 $20.50
Saving Flag Settings Example void outputstuff(ofstream& outstream) { //save precision setting int precisionsetting = outstream.precision(); //save flag setting long flagsettings = outstream.flags(); outstream.setf(ios::fixed ios::showpoint); outstream.precision(2); //restor precision setting outstream.precision(precisionsetting); //restore flag setting outstream.flags(flagsettings); }
Restoring Default setf Settings cout.setf(0, ios::floatfield); 預設旗標設定會隨著不同編譯器而不同 有效小數位數的設定不受影響
Stream Hierarchies
Random Access to Files 循序存取 (Sequential Access) 只能從頭開始存取, 直到抵達目標存取位置 一般的檔案操作模式 隨機存取 (Random Access) 可隨意存取到檔案任何地方的資料 使用 fstream ( 檔案串流含 ifstream 合 ofstream) 物件可達此目的
Random Access Tools 開啟 fstream 的方法 fstream rwstream; rwstream.open("stuff", ios::in ios:: out); // 上面二指令是開啟一個同時可讀可寫檔案的好方法 在 fstream 中移動讀取頭和寫入頭 rwstream.seekp(1000); Positions put-pointer at 1000 th byte rwstream.seekg(1000); // 寫入頭定位 // 讀取頭定位 Positions get-pointer at 1000 th byte 在 fstream 中取得讀取頭和寫入頭位置 tellp(); tellg();
seekp()/seekg() off: an Integral value representing the offset to be applied relative to an absolute position specified in the dir parameter. dir: Seeking direction that specifies an absolute position from where the offset parameter off is applied.
例題 : 隨機寫入檔案 int main () { long pos; ofstream outfile; outfile.open ("test.txt"); outfile.write ("This is an apple",16); pos=outfile.tellp(); outfile.seekp (pos-7); outfile.write (" sam",4); outfile.close(); return 0; }
Random Access Sizes 讀取或寫入物件資料 必須知道物件所占記憶體大小 例如 : Position put-pointer at 100 th record of objects: rwstream.seekp(100*sizeof(myobject) 1);
String Streams 被連結到 string( 字串 ) 的串流 字串串流提供記憶體 (in-memory) 中的輸出 / 入 種類 輸入字串串流 (istringstream): 從字串讀取資料 輸出字串串流 (ostringstream): 把資料寫入字串 字串串流 (stringstream): 讀寫資料到字串 此串流衍生自 iostream 類別, 相關定義在 <sstream> 標頭檔中 stringstream 和 fstream 二類別並無關聯性
Specific Operations of String Streams stringstream strm; 宣告一個空的 stringstream stringstream strm(s); 宣告一個空的 stringstream 並將其字串內容初始化為 s strm.str() 傳回此 stringstream 物件的字串值 strm.str(s) 指定此 stringstream 物件的字串值為 s, 如果 s=, 則清空其字串內容
例題 : 使用 stringstream string line, word; // will hold a line and word from input, respectively while (getline(cin, line)) { // read a line from the input into line // do per-line processing istringstream stream(line); // bind stream to the line we read while (stream >> word){ // read a word from line // do per-word processing } }
Conversion and Formatting across Multiple Data Types using ostringstreams 各種資料形態的資料都能透過字串串流做格式化編排後轉換為字串 int val1 = 512, val2 = 1024; ostringstream format_message; // ok: converts values to a string representation format_message << "val1: " << val1 << "\n" << "val2: " << val2 << "\n"; format_message val1: 512\nval2: 1024
Retrieve Data Values using istringstreams istringstream input_istring(format_message.str()); string dump; //converting back to arithmetic types input_istring >> dump >> val1 >> dump >> val2; cout << val1 << " " << val2 << endl; // prints 512 1024