460 likes | 547 Views
15.1 磁碟檔案 15-2 15.1.1 什麼是檔案 15-2 15.1.2 檔案名稱 15-2 15.1.3 開啟檔案 open 15-3 15.1.4 檔案是否開啟成功 15-6 15.1.5 關閉檔案 close 15-7 15.2 存取文字檔 15-7 15.2.1 寫入文字檔 << 15-8 15.2.2 附加資料到文字檔 << 15-9 15.2.3 讀取文字檔 >> 15-11 15.2.4 寫入單一字元 put 15-12 15.2.5 讀取單一字元 get 15-13.
E N D
15.1磁碟檔案 15-2 15.1.1 什麼是檔案 15-2 15.1.2 檔案名稱 15-2 15.1.3 開啟檔案open 15-3 15.1.4 檔案是否開啟成功 15-6 15.1.5 關閉檔案close 15-7 15.2存取文字檔 15-7 15.2.1 寫入文字檔 << 15-8 15.2.2 附加資料到文字檔 << 15-9 15.2.3 讀取文字檔 >> 15-11 15.2.4 寫入單一字元put 15-12 15.2.5 讀取單一字元get 15-13 15.3存取二進位檔 15-17 15.3.1 寫入二進位檔write 15-17 15.3.2 附加資料到二進位檔write 15-19 15.3.3 讀取二進位檔read 15-22 15.3.4 檔案結束位置eof 15-24 15.4隨機存取資料 15-28 15.4.1 移動讀取指標seekg 15-29 15.4.2 移動寫入指標seekp 15-29 15.4.3 取得讀取指標tellg 15-32 15.4.4 取得寫入指標tellp 15-32 15 檔案管理
15.1 磁碟檔案 • 因為結束程式或關閉電源都將使得存在記憶體中的資料消失,所以每次執行前幾章的學生資料程式或員工資料程式時,都必須重新輸入資料。 • 如果經常要使用這些資料,則可以在結束程式或關閉電源以前將資料存入磁碟檔案中,下次要用時再從磁碟檔案中讀取。
15.1.1 什麼是檔案 • 在許多程式中,檔案(file)是基本的輸入與輸出物件。檔案物件(file object)收集了磁碟檔案資訊,包括檔案是否存在或開啟,以及存取檔案的路徑、大小、日期、與時間等等,所以可以利用檔案物件開啟、讀取、寫入、關閉、與取得磁碟檔案的資料。
15.1.2 檔案名稱 • 所有的檔案都有一個可讓作業系統與使用者確認的獨一無二的檔名。每個作業系統都有它們自己的檔案命名方式,例如Windows可以接受長檔名,而MS-DOS則只接受短檔名(主檔名8個字元,副檔名3個字元)。 • 基本上檔名分為主檔名與副檔名,而且主檔名與副檔名中間以句點(.)隔開。一般而言,副檔名代表檔案的種類。
15.1.3 開啟檔案open • #include <fstream.h> • ifstream 輸入物件; //建立輸入檔案物件ofstream 輸出物件; //建立輸出檔案物件fstream 輸出入物件; //建立輸入輸出檔案物件 • 檔案物件.open(“檔案名稱”, ios::開啟模式);
15.1.3 開啟檔案open (續) • 先建立檔案物件,再開啟資料檔 ofstream out; //建立輸出檔案物件 ifstream in; //建立輸入檔案物件 fstream io; //建立輸入輸出檔案物件 out.open("a:\\textOut.txt", ios::out); //開啟輸出檔案 in.open("a:\\textIn.txt", ios::in); //開啟輸入檔案 io.open("a:\\textIO.txt", ios::in|ios::out); //開啟輸入輸出檔案
15.1.3 開啟檔案open (續) • 先建立檔案物件,再開啟二進位檔案 ofstream out; //建立輸出檔案物件 ifstream in; //建立輸入檔案物件 fstream io; //建立輸入輸出檔案物件 out.open("textOut.txt", ios::binary|ios::out); //開啟二進位輸出檔案 in.open("textIn.txt", ios::binary|ios::in); //開啟二進位輸入檔案 io.open("textIO.txt", ios::binary|ios::in|ios::out); //開啟二進位輸入輸出
15.1.3 開啟檔案open (續) • 建立同時開啟資料檔案 //使用ofstream的建立者函數建立物件並開啟輸出檔案 • ofstream out("a:\\textOut.dat", ios::out); //使用ifstream的建立者函數建立物件並開啟輸入檔案 • ifstream in("a:\\textIn.dat", ios::in); //使用fstream的建立者函數建立物件並開啟輸入輸出檔案 • fstream io("a:\\textIO.dat", ios::in, ios::out);
15.1.3 開啟檔案open (續) • 建立同時開啟二進位檔案 //使用ofstream的建立者函數建立物件並開啟輸出檔案 • ofstream out("a:\\textOut.dat", ios::binary|ios::out); //使用ifstream的建立者函數建立物件並開啟輸入檔案 • ifstream in("a:\\textIn.dat", ios::binary|ios::in); //使用fstream的建立者函數建立物件並開啟輸入輸出檔案 • fstream io("a:\\textIO.dat", ios::binary|ios::in|ios::out);
15.1.4 檔案是否開啟成功 • 在呼叫open函數後,必須先測試檔案是否開啟成功,然後才可正確存取檔案資料。 ifstream myFile; //建立輸入檔案物件 in.open("a:\\textIn.txt", ios::in); //開啟輸入檔案 if(!myFile) //測試檔案是否開啟成功 cout << "開啟檔案失敗!\n"; //檔案代號錯誤
15.1.4 檔案是否開啟成功 (續) • 當使用建立者函數建立檔案物件並開啟檔案時,則可用is_open() 函數來判斷檔案開啟是否成功 ifstream myFile("a:\\textIn.txt", ios::in); //建立並開啟檔案 if(!myFile.is_open())//測試檔案是否開啟成功 cout << "開啟檔案失敗!\n"; //檔案代號錯誤
15.1.5 關閉檔案close • #include <fstream> • 物件名稱.close(); • 範例 myFile.close(); //關閉myFile檔案物件
15.2 存取文字檔 • 一般文字編輯軟體都是將資料存入文字檔,例如微軟的NotePad就是將文件存入 .txt檔,而WordPad與Word則是將文件存入 .doc檔。所以本節將要介紹如何寫入資料至文字檔、如何附加資料到文字檔、與讀取文字檔資料等等。
15.2.1 寫入文字檔 << • 物件名稱.open(“檔案名稱”, ios::out); //開啟檔案 • 物件名稱 << 輸出字串; //寫入檔案 • 範例一 ofstream filePtr; //建立檔案物件filePtr filePtr.open("a:\\textIO.txt", ios::out);//開啟檔案a:\textIO.txt filePtr << "Life is not easy, but in the long run \n"; filePtr << "it's easier than going to elaborate ends \n"; filePtr << "to deny it.\n"; //寫入字串到檔案 filePtr.close(); //關閉filePtr檔案物件
15.2.1 寫入文字檔 << (續) • 範例二 int id; //宣告整數變數 char name[40]; //宣告C型態字串變數 ofstream outFile; //建立檔案物件outFile outFile.open(“a:\\textIO.dat”, ios::out); //開啟檔案a:\textIO.dat cin >> id >> name; //從鍵盤讀取整數與字串 outFile << id << '\t' << name << '\n'; //寫入整數與字串到檔案 outFile.close(); //關閉outFile檔案物件
15.2.2 附加資料到文字檔 << • 物件名稱.open(“檔案名稱”, ios::app); //開啟檔案 • 物件名稱 << 字串1 << 字串2; //附加資料 • 範例一 ofstream filePtr; //建立檔案物件filePtr filePtr.open("a:\\outFile.txt", ios::app); //開啟a:\outFile.txt filePtr << "人生的確不是簡單的,可是老老實實地活著, \n"; //附加字串到檔案 filePtr << "總要比想出千方百計的逃避人生來得簡單些。 \n"; //附加字串到檔案 filePtr.close();
15.2.2 附加資料到文字檔 << (續) • 範例二 int id; //宣告整數變數 char name[40]; //宣告C型態字串變數 ofstream outFile; //建立檔案物件outFile outFile.open("a:\\textIO.dat", ios::app); //開啟檔案a:\textIO.dat cin >> id >> name; //從鍵盤讀取整數與字串 outFile << id << '\t' << name << '\n'; //寫入整數與字串到檔案 outFile.close(); //關閉outFile檔案物件
15.2.3 讀取文字檔 >> • 物件名稱.open(“檔案名稱”, ios::in);//開啟檔案 • 物件名稱 >> 緩衝區1 >> 緩衝區2; //讀取資料 • 範例 ifstream outFile; //建立檔案物件outFile int id; //存放資料緩衝區 char name[40]; //存放資料緩衝區 • 範例待續……
15.2.3 讀取文字檔 >> (續) outFile.open("a:textIO.dat", ios::in); //開啟輸入檔a:\textIO.dat outFile >> id >> name; //讀取檔案存入緩衝區 while(!outFile.eof()) { //是否已到檔尾 cout << id << '\t' << name << endl; //顯示緩衝區資料 outFile >> id >> name; //讀取檔案存入緩衝區 } outFile.close(); //關閉檔案物件outFile
15.2.4 寫入單一字元put • 物件名稱.open(“檔案名稱”, ios::out); //開啟檔案 • 物件名稱.put(字元緩衝區); //寫入資料 • 範例 ofstream filePtr; //建立檔案物件filePtr char inData[] = "Life is not easy, but in the long run \n" "it's easier than going to elaborate ends \n" "to deny it.\n"; • 範例待續……
15.2.4 寫入單一字元put (續) • 範例續 filePtr.open("a:\\textIO.txt", ios::in); //開啟輸入檔a:\textIO.txt int len = strlen(inData); //取得inData陣列的長度 for(int i=0; i<len; i++) { //寫入字元迴圈 filePtr.put(inData[i]); //寫入字元到textIO.txt } filePtr.close(); //關閉檔案物件filePtr
15.2.5 讀取單一字元get • 物件名稱.open(“檔案名稱”, ios::in); //開啟檔案 • 物件名稱.get(字元緩衝區); //讀取資料 • 範例 ifstream filePtr; //建立檔案物件filePtr char inData; //存放資料緩衝區 filePtr.open("a:\\textIO.txt", ios::in); //開啟輸出檔a:\textIO.txt while(filePtr.get(inData)) { //取得資料並存入緩衝區 cout << inData; //顯示資料 } filePtr.close(); //關閉檔案物件filePtr
Exercise • 用C++寫一個檔案複製的程式 • 下載f1.txt • 寫一個程式,利用檔案讀取及檔案寫入的方式,將f1.txt複製為f2.txt
15.3 存取二進位檔 • 雖然讀寫格式化的文字檔非常簡單,也非常適用於文件檔案的存取,但它不是最有效的檔案管理方式。所以現在要介紹另一種的檔案管理方式:非格式化的二進位檔。
15.3.1 寫入二進位檔write • 物件名稱.open(“檔案名稱”, ios::binary); //開啟二進位檔 • 物件名稱.write(const char *緩衝區, 寫入長度);//寫入資料 • 範例 class Student { //自定Student資料 int student_id; char student_name[40]; public: Student() { Student_id = 10; Student_name = "Tom"; } };
15.3.1 寫入二進位檔write (續) • 範例續 int main() { Student stuData; //建立類別物件 ofstream filePtr; //建立輸出檔案物件 filePtr.open("a:\\binIO.dat", ios::binary|ios::out); //開啟二進位檔 filePtr.write((char*)&stuData, sizeof(stuData)); //緩衝區資料寫入檔案 filePtr.close(); return 0; //正常結束程式 }
15.3.2 附加資料到二進位檔write • 物件名稱.open(“檔案名稱”, ios::binary | ios::app); • 物件名稱.write(const char *緩衝區, 寫入長度); class Student { //自定Student資料 int student_id; char student_name[40]; public: setData(id, name) { student_id = id; student_name = name; } };
15.3.2 附加資料到二進位檔write (續) • 範例續 int main() { Student stuData; //建立類別物件 ofstream filePtr; //建立輸出檔案物件 filePtr.open("a:\\binIO.dat ", ios::binary|ios::app); //開啟二進位附加檔 stuData.setData(1, "Ken"); //設定自定資料 filePtr.write((char*)&stuData, sizeof(stuData)); //緩衝區資料附加到檔案 filePtr.close(); return 0; //正常結束程式 }
15.3.3 讀取二進位檔read • 物件名稱.open(“檔案名稱”, ios::binary | ios::in); • 物件名稱.read(const char *緩衝區, 讀取長度); • 範例 class Student { //自定Student資料 int student_id; char student_name[40]; public: void showData() { cout << student_id << '\t' << student_name << endl; } };
15.3.3 讀取二進位檔read (續) • 範例續 int main() { Student stuData; //建立類別物件 ifstream filePtr; //建立輸出檔案物件 filePtr.open("a:\\binIO.dat", ios::binary|ios::in); filePtr.read((char*)&stuData, //讀取資料到緩衝區 sizeof(stuData)); //讀取長度=緩衝區大小 stuData.showdata(); //呼叫顯示資料函數 filePtr.close(); return 0; //正常結束程式 }
15.3.4 檔案結束位置eof • 輸入檔案物件.eof() • 範例 class Student { // 自定Student資料 int student_id; char student_name[40]; public: void showData() { cout << student_id << '\t' << student_name << endl; } };
15.3.4 檔案結束位置eof (續) • 範例續 int main() { Student stuData; //建立類別物件 ifstream filePtr; //建立輸出檔案物件 filePtr.open("a:\\binIO.dat", ios::binary|ios::in); //開啟二進位附加檔 filePtr.read((char*)&stuData, //讀取資料到緩衝區 sizeof(stuData)); //讀取長度=緩衝區大小
15.3.4 檔案結束位置eof (續) • 範例續 while(!filePtr.eof()) { //讀取資料迴圈 stuData.showdata(); //呼叫顯示資料函數 filePtr.read((char*) &stuData, //讀取資料到緩衝區 sizeof(stuData)); //讀取長度=緩衝區大小 } filePtr.close(); return 0; //正常結束程式 }
Exercise • 寫一個C++程式處理影像檔 • 下載lena1.raw • 用photoshop瀏覽lena1.raw • 寫一個程式,利用檔案讀取及檔案寫入的方式,將lena1.raw複製為lena2.raw,但請將每一個字元的值c改為(255-c),再寫入lena2.raw • 注意c的型態應改為unsigned char • 用photoshop瀏覽lena2.raw
15.4 隨機存取資料 • 文字檔是一個字元或一個字串為單位,而二進位檔則是以一筆資料為單位,所以二進位檔案的優點就是可以隨機存取檔案內的資料,也就是說可以任意存取二進位檔中的任何一筆資料。
15.4.1 移動讀取指標seekg • 輸入檔案物件.seekg(移動距離, ios::起始位置)
15.4.2 移動寫入指標seekp • 輸出檔案物件.seekp(移動距離, ios::起始位置)
15.4.2 移動寫入指標seekp (續) class Student { //自定Student資料 int student_id; char student_name[40]; public: void showData() { cout << student_id << '\t' << student_name << endl; } };
15.4.2 移動寫入指標seekp (續) • 範例續 int main() { Student stuData; //建立類別物件 ifstream filePtr; //建立輸出檔案物件 filePtr.open("a:\\binIO.dat", ios::binary|ios::in); int n; cin >> n; int len = sizeof(stuData); //計算每筆資料長度 int pos = (n-1) * len; //計算第n筆資料位置 filePtr.seekg(pos, ios::beg); //移動get指標 filePtr.read((char*)&stuData, sizeof(stuData));//讀取資料 stuData.showdata(); //呼叫顯示資料函數 filePtr.close(); return 0; //正常結束程式 }
15.4.3 取得讀取指標tellg • 輸入檔案物件.tellg() 15.4.4 取得寫入指標tellp • 輸出檔案物件.tellp()
15.4.4 取得寫入指標tellp (續) • 範例一 int main() { ifstream filePtr; //建立輸出檔案物件 filePtr.open("a:\\binIO.dat", ios::binary|ios::in); filePtr.seekg(0, ios::end); //移動指標到檔尾 int endpos = filePtr.tellg(); //取得指標位置 cout << "a:\\binIO.dat 的大小 = " << endpos << " bytes" << endl; //顯示檔案大小 filePtr.close(); return 0; //正常結束程式 }
15.4.4 取得寫入指標tellp (續) • 範例二 class Student { int student_id; char student_name[40]; }; int main() { ifstream filePtr; //建立輸出檔案物件 filePtr.open("a:\\binIO.dat", ios::binary|ios::in); //開啟二進位輸入檔 filePtr.seekg(0, ios::end); //移動指標到檔尾 int endpos = filePtr.tellg(); //取得檔案位元組數 int n = endpos / sizeof(stuData); //除以緩衝器大小 cout << "a:\\binIO.dat 共有 " << n << " 筆資料"; //顯示資料筆數 filePtr.close(); return 0; //正常結束程式 }
Exercise • 下載C1505.dat • 使用課本範例程式15-09中的class Student • 將C1505.dat中的學生資料依序逐筆印出 • 可參考課本範例程式15-09,10,11的程式內容