69
1 1 /69 /69 Chap 12 Chap 12 資資資資資資資資資 資資資資資資資資資 如如如如如如如如如如如如如如如如如如如如 如如如如如如如如如如 如如如如如如如如如如如如如如如如如如如如 如如如如如如如如如如 如如如 如如如如如如如如 如如如如如如如如如如如如如如 如如如如如如如如如 一,。, 如如如 如如如如如如如如 如如如如如如如如如如如如如如 如如如如如如如如如 一,。, 如如如如如如如如如如如如如如

Chap 12 資料流與檔案的存取

Embed Size (px)

DESCRIPTION

Chap 12 資料流與檔案的存取. 如果程式所處理的資料只能寫在原始程式內部,或以互動的方式由鍵盤逐一輸入,則功能將很有限。本章探討如何從檔案讀取資料,以及將處理後的資料存入檔案的方法。. 資料流與檔案的存取. 12.1  資料流 12.2  檔案的存取 12.3  檔案的存取模式 12.4  資料的讀取與寫入 12.5  檔案內容的位置標記 12.6  將檔案的存取寫成函數. 資料流 (stream). 回顧標準的輸出入管道 cout 和 cin : 範例程式 檔案 BasicIO.cpp // BasicIO.cpp - PowerPoint PPT Presentation

Citation preview

11/69/69

Chap 12 Chap 12 資料流與檔案的存取資料流與檔案的存取

如果程式所處理的資料只能寫在原始程式內如果程式所處理的資料只能寫在原始程式內部,或以互動的方式由鍵盤逐一輸入,則功能將很有部,或以互動的方式由鍵盤逐一輸入,則功能將很有限。本章探討如何從檔案讀取資料,以及將處理後的限。本章探討如何從檔案讀取資料,以及將處理後的資料存入檔案的方法。資料存入檔案的方法。

22/70/70

資料流與檔案的存取 資料流與檔案的存取

12.112.1  資料流 資料流 12.212.2  檔案的存取 檔案的存取 12.312.3  檔案的存取模式 檔案的存取模式 12.412.4  資料的讀取與寫入 資料的讀取與寫入 12.512.5  檔案內容的位置標記 檔案內容的位置標記 12.612.6  將檔案的存取寫成函數 將檔案的存取寫成函數

33/70/70

資料流 資料流 (stream) (stream)

回顧標準的輸出入管道回顧標準的輸出入管道 coutcout 和和 cincin ::

範例程式 檔案 範例程式 檔案 BasicIO.cppBasicIO.cpp// BasicIO.cpp// BasicIO.cpp#include <#include <iostreamiostream>>using namespace stdusing namespace std;;int main ()int main (){{

int N;int N;coutcout << “<< “ 請輸入一個整數請輸入一個整數 :” :” << endl;<< endl;cincin >> N;>> N;coutcout << “<< “ 您輸入的是 “ 您輸入的是 “ << N << endl;<< N << endl;return 0;return 0;

} }

44/70/70

操作結果 操作結果

請輸入一個整數:請輸入一個整數:45634563

您輸入的是 您輸入的是 45634563

55/70/70

資料流 資料流 (stream)(stream)和資料流物件和資料流物件 (stream object)(stream object)

cout 是聯結程式和顯示器的管道,而 cin 是聯結程式和鍵盤的管道。

單向的資料流通管道為資料流 (stream) 。 cin 是一個輸入資料流物件 (input stream obje

ct) 。 cout 是一個輸出資料流物件 (output stream o

bject) 。

66/70/70

物件 物件 (object) (object) 和類別 和類別 (class) (class)

物件物件 (object)(object) ,其原文有「個體」、「對象」,其原文有「個體」、「對象」等多種意涵。等多種意涵。

類別類別是一種廣義的資料型態,它可以由程式是一種廣義的資料型態,它可以由程式寫作者自行定義。寫作者自行定義。

由類別定義的「物件」不僅包括資料,而且由類別定義的「物件」不僅包括資料,而且還包括與物件進行互動所需要的各種函數。還包括與物件進行互動所需要的各種函數。

cincin 和和 coutcout 分別屬於分別屬於 istreamistream 和和 ostreamostream 兩個類兩個類別。我們不需要定義別。我們不需要定義 cincin 和和 coutcout ,因為它們,因為它們是最常用的預設物件。 是最常用的預設物件。

77/70/70

驅動程式 驅動程式

驅動程式 驅動程式 (drivers) (drivers) 是作業系統 是作業系統 (( 例如例如 WindowsWindows 和和 LiLinux) nux) 的一部份,用來與硬體 的一部份,用來與硬體 (( 譬如鍵盤和顯示器譬如鍵盤和顯示器 ) ) 溝溝通,以處理硬體裝置與記憶體之間的資料流動。如下通,以處理硬體裝置與記憶體之間的資料流動。如下圖所示:圖所示:

資料流 資料流 (stream) (stream) 與硬體之間的關係圖與硬體之間的關係圖

C++ 程式

Buffer

Buffer

cout

cin

顯示器

鍵盤

記憶體

88/70/70

使用成員函數 使用成員函數 (member functions) (member functions) 的語的語法法

類別類別 (Class) (Class) 內部所定義的各種函數稱為內部所定義的各種函數稱為成員成員函數函數 (member functions) (member functions) 或或方法方法 (methods)(methods) 。。

敘述敘述 cin.get(Ch);cin.get(Ch);

裏,句點「裏,句點「 .. 」稱為」稱為成員運算符號成員運算符號 (member (member operator)operator) ,它的前面是物件的名稱,而其後是,它的前面是物件的名稱,而其後是成員函數的名稱。成員函數的名稱。

99/70/70

呼叫物件呼叫物件 cincin 的成員函數的成員函數 get()get()

cin.get (Ch);

成員函數

物件名稱 引數

1010/70/70

檔案檔案

在一個名稱之下,內含有資料的獨立儲在一個名稱之下,內含有資料的獨立儲存單位。檔案通常儲存於硬碟、磁片、存單位。檔案通常儲存於硬碟、磁片、光碟、磁帶或 光碟、磁帶或 MO MO 等媒體上。等媒體上。

1111/70/70

檔案的存取檔案的存取1.1. 程式開頭要加入標頭檔程式開頭要加入標頭檔 : : <fstream><fstream> ,以含入必要,以含入必要

的類別宣告。的類別宣告。2.2. 必需明確地宣告和定義讀寫檔案所需的管道 必需明確地宣告和定義讀寫檔案所需的管道 (( 亦即亦即

資料流資料流 )) 。。例如:例如:

要讀取檔案時,定義類別為要讀取檔案時,定義類別為 ifstream ifstream 的輸入的輸入型檔案資料流:型檔案資料流:

ifstream ifstream FileInputFileInput;; 要寫入檔案時,則需定義類別為要寫入檔案時,則需定義類別為 ofstreamofstream 的輸出的輸出

型檔案資料流:型檔案資料流: ofstream ofstream FileOutputFileOutput;; 讀寫檔案前,需要先執行將檔案「開啟」 讀寫檔案前,需要先執行將檔案「開啟」 (open) (open)

的動作。讀寫完畢後,最好執行將檔案「關閉」的動作。讀寫完畢後,最好執行將檔案「關閉」 (clo(close) se) 的動作。的動作。

1212/70/70

檔案和程式、資料流之間的關係檔案和程式、資料流之間的關係

C++ 程式

暫存器 (register)

輸入檔案資料流

記憶體

輸出檔案資料流

儲存裝置

驅動程式

1313/70/70

資料存取的語法資料存取的語法

一旦檔案被開啟,則資料存取的語法和一旦檔案被開啟,則資料存取的語法和先前先前 cincin 、、 coutcout 的用法相同。例如:的用法相同。例如:

FileInputFileInput >> x; >> x;

FileOutputFileOutput << x << endl << x << endl 程式內部所直接使用的是各個「已經聯程式內部所直接使用的是各個「已經聯結到特定檔案的檔案資料流」,而不再結到特定檔案的檔案資料流」,而不再提及檔案的名稱。提及檔案的名稱。

1414/70/70

將資料流聯結到檔案的語法將資料流聯結到檔案的語法

例如,在檔案開啟時將敘述寫成:例如,在檔案開啟時將敘述寫成:FileInput.FileInput.open(“FileA.txt”);open(“FileA.txt”);

檔案關閉時,則不用再寫出檔案名稱,檔案關閉時,則不用再寫出檔案名稱,只需寫成:只需寫成:FileInput.FileInput.close();close();

1515/70/70

範例程式範例程式 TaxFile.cppTaxFile.cpp

從檔案從檔案 Income.txtIncome.txt 將收入的數值讀到變數將收入的數值讀到變數 IncIncomeome 裏,再呼叫函數裏,再呼叫函數 CalculateTax() CalculateTax() 以計算稅以計算稅額額 TaxTax ,最後把稅額的數值輸出到顯示器,,最後把稅額的數值輸出到顯示器,並同時存到檔案並同時存到檔案 Tax.txtTax.txt 裏。裏。

示範了如何宣告資料流,如何開啟和關閉檔示範了如何宣告資料流,如何開啟和關閉檔案,以及如何在檔案裏存取資料的細節。案,以及如何在檔案裏存取資料的細節。

1616/70/70

範例程式 檔案 範例程式 檔案 TaxFile.cpp TaxFile.cpp

// TaxFile.cpp// TaxFile.cpp#include <iostream>#include <iostream>#include <fstream>#include <fstream>using namespace std;using namespace std;double CalculateTax(double); // double CalculateTax(double); // 函數的宣告函數的宣告// ---// --- 主程式主程式 ------------------------------------------------int main()int main(){{ char*char* FileNameIn = "Income.txt"; // FileNameIn = "Income.txt"; // 以字串的以字串的

方式宣告檔名方式宣告檔名 char*char* FileNameOut = "Tax.txt"; FileNameOut = "Tax.txt"; double Income, Tax;double Income, Tax; ifstreamifstream FileInputFileInput;; ofstreamofstream FileOutputFileOutput;; FileInput.open (FileInput.open ( FileNameIn FileNameIn );); FileOutput.open(FileOutput.open( FileNameOut FileNameOut ););

1717/70/70

if (!if (!FileInputFileInput)) {{ cout << "cout << " 檔案檔案 : " : " << FileNameIn<< FileNameIn

<< " << " 開啟失敗開啟失敗 !"!" << endl; exit(1);<< endl; exit(1); }} if (!if (!FileOutputFileOutput)) {{ cout << "cout << " 檔案檔案 : ": " << FileNameOut<< FileNameOut

<< " << " 存檔失敗存檔失敗 !"!" << endl; exit(1);<< endl; exit(1); }} FileInput >>FileInput >> Income Income;; Tax = Tax = CalculateTax(Income);CalculateTax(Income); cout cout << "<< " 您要繳的綜合所得稅是您要繳的綜合所得稅是 : ": " << Tax << " << Tax << " 元元 "; ";

1818/70/70

FileOutput <<FileOutput << " " 您要繳的綜合所得稅是您要繳的綜合所得稅是 : ": " <<<< Tax Tax << << " " 元元 "";; FileInput.close(); FileInput.close(); // // 關閉輸入檔案關閉輸入檔案 FileOutput.close(); FileOutput.close(); // // 關閉輸出檔案關閉輸出檔案 return 0;return 0;}}// ---// --- 函數 函數 CalculateTax() CalculateTax() 的定義的定義 ----------// // 改寫自改寫自 4.44.4 節「巢狀節「巢狀 if-elseif-else 敘述」敘述」// // 程式 程式 Tax.cpp Tax.cpp 以計算稅額以計算稅額double CalculateTax(double GIncome)double CalculateTax(double GIncome){{ double Tax;double Tax; if (GIncome < 0.0)if (GIncome < 0.0) cout << "cout << " 您輸入的綜合所得淨額沒有意義您輸入的綜合所得淨額沒有意義 !\n";!\n"; else if (GIncome < 330000.0)else if (GIncome < 330000.0) Tax = GIncome * 0.06;Tax = GIncome * 0.06;

1919/70/70

else if (GIncome < 890000.0)else if (GIncome < 890000.0) Tax = GIncome * 0.13 - 23100;Tax = GIncome * 0.13 - 23100; else if (GIncome < 1780000.0)else if (GIncome < 1780000.0) Tax = GIncome * 0.21 - 94300;Tax = GIncome * 0.21 - 94300; else if (GIncome < 3340000.0)else if (GIncome < 3340000.0) Tax = GIncome * 0.3 - 254500;Tax = GIncome * 0.3 - 254500; elseelse Tax = GIncome * 0.4 - 588500;Tax = GIncome * 0.4 - 588500; return Tax;return Tax;} }

2020/70/70

操作結果 操作結果

您要繳的綜合所得稅是:您要繳的綜合所得稅是: 50715.250715.2 元 元

2121/70/70

檔案的存取模式檔案的存取模式

1.1. createcreate ( ( 創造創造 ) ) 和和 replacereplace ( ( 取代取代 ): ): 如果如果檔案不存在,要不要產生一個新的檔案,檔案不存在,要不要產生一個新的檔案,如果檔案已經存在,要不要將其取代。如果檔案已經存在,要不要將其取代。

2.2. appendappend ( ( 附加附加 ) ) 和 和 replacereplace ( ( 取代取代 ): ): 從從資料流輸入的資料要接在原來的內容之資料流輸入的資料要接在原來的內容之後,還是要取代原來的內容。後,還是要取代原來的內容。

2222/70/70

另外一種檢查開檔動作有沒有失敗的語法 另外一種檢查開檔動作有沒有失敗的語法

將開檔部份的敘述改寫如下:將開檔部份的敘述改寫如下:

FileInput.FileInput.open (FileNameIn, open (FileNameIn, ios::nocreateios::nocreate););

if (if (FileInput.FileInput.fail())fail())

{{

cout << "cout << " 檔案: 檔案: " " << FileNameIn<< FileNameIn

<< " << " 開啟失敗開啟失敗 !" !" << endl; << endl;

exit(1); exit(1);

}}

2323/70/70

結合資料流的宣告敘述和開檔的動作結合資料流的宣告敘述和開檔的動作

如果檔案資料流如果檔案資料流 FileInputFileInput 在程式中只在程式中只跟一個檔案聯結,則可以進一步寫成:跟一個檔案聯結,則可以進一步寫成:

ifstream FileInputifstream FileInput (FileName, (FileName, ios::nocreateios::nocreate););

參數 參數 nocreate nocreate 又稱為又稱為模式指示參數模式指示參數 (mode indicator)(mode indicator) 。。

2424/70/70

常用的模式指示參數常用的模式指示參數 (mode indicator)(mode indicator)

模式指示參數 開檔模式

ios::in 將檔案開啟成輸入模式。

ios::out 將檔案開啟成輸出模式,如果已有同名舊檔則將其取代。

ios::app 開啟為 append (添加)模式。

ios::ate 移到所開啟檔案的結尾處。

ios::binary 將開啟的檔案內容視為二進位碼。 ( 預設模式為「文字」)

ios::trunc 如果檔案已經存在,則將其內容清除。

ios::nocreate 只用來開啟舊檔作為輸出之用,如果檔案不存在就放棄。

ios::noreplace 只用來開啟新檔作為輸出之用,如果已有舊檔就放棄。

2525/70/70

統一使用統一使用 fstreamfstream 類別其後區別該資料流的方類別其後區別該資料流的方向向

fstream FileInput; fstream FileInput;

fstream FileOutPut;fstream FileOutPut;

FileInput.openFileInput.open(FileName, (FileName, ios::inios::in););

FileOutput.openFileOutput.open(FileName, (FileName, ios::outios::out););

2626/70/70

結合模式指示參數結合模式指示參數

進一步決定「如果要開啟以供輸入的檔進一步決定「如果要開啟以供輸入的檔案不存在」的處理方式,使用「案不存在」的處理方式,使用「或或」 」 (( 也就是也就是 or) or) 的語法:的語法:

FileInput.openFileInput.open(FileName, (FileName, ios::in | ios::nocreaios::in | ios::nocreatete););

2727/70/70

EOF (end-of-file)EOF (end-of-file)

檔案的結束記號。檔案的結束記號。 EOFEOF 為標頭檔 為標頭檔 <fstream> <fstream> 內定義的常內定義的常數。數。

它在它在 WindowsWindows 和和 DOSDOS 作業系統都是使作業系統都是使用第用第 2626 個個 ASCIIASCII 字元‘字元‘ Ctrl-Z’Ctrl-Z’ ,在某,在某些作業系統內些作業系統內 EOFEOF 的值設為 –的值設為 – 11 。。

2828/70/70

範例程式範例程式 ConvFile.cppConvFile.cpp

使用本節介紹的語法進行讀檔與存檔的使用本節介紹的語法進行讀檔與存檔的操作。操作。首先從檔案首先從檔案 Original.txt Original.txt 逐一讀進字母,逐一讀進字母,再經 再經 <cctype> <cctype> 中的函數中的函數 toupper()toupper() 將字將字母轉換為大寫字母後,逐一存進檔案母轉換為大寫字母後,逐一存進檔案 CConverted.txt onverted.txt 中。中。

2929/70/70

範例程式 檔案 範例程式 檔案 ConvFile.cppConvFile.cpp

// ConvFile.cpp// ConvFile.cpp#include <iomanip>#include <iomanip>#include <iostream>#include <iostream>#include <fstream>#include <fstream>#include <cctype>#include <cctype>using namespace std;using namespace std;char* FileNameIn = "Original.txt";char* FileNameIn = "Original.txt";char* FileNameOut = "Converted.txt";char* FileNameOut = "Converted.txt";// ---// --- 函數 函數 Sort() Sort() 的宣告的宣告 --------int Sort(char X);int Sort(char X);// ---// --- 主程式主程式 ------------------------------------------------int main()int main(){{

3030/70/70

char C;char C; fstream FileInput(fstream FileInput(FileNameInFileNameIn, ios::in);, ios::in); if (!if (!FileInputFileInput)) {{ cout << "cout << "檔案檔案 : " << FileNameIn: " << FileNameIn << " << " 開啟失敗開啟失敗 !" << endl; !" << endl; exit(1);exit(1); }} fstream FileOutput(fstream FileOutput(FileNameOutFileNameOut, ios::out);, ios::out); if (!if (!FileOutputFileOutput)) {{ cout << "cout << "檔案檔案 : << FileNameOut: << FileNameOut << " << " 存檔失敗存檔失敗 !" << endl; !" << endl; exit(1);exit(1); }}

3131/70/70

while ((C = while ((C = FileInput.get()FileInput.get())!= )!= EOFEOF)) { switch (Sort(C)){ switch (Sort(C)) {{ case 1:case 1: FileOutputFileOutput << char( << char(toupper(toupper(CC)));); break;break; case 0: case 2:case 0: case 2:

case 3: case 4:case 3: case 4: FileOutput FileOutput << C ;<< C ; break;break; case 5:case 5: FileOutputFileOutput << "Other" << endl; << "Other" << endl; break;break; default:default: cout << "cout << "程式有問題程式有問題 !" << endl;!" << endl; }}

}}

3232/70/70

FileOutputFileOutput.close();.close(); FileInputFileInput.close(); .close(); cout << "cout << " 成功存於檔案 成功存於檔案 " << FileNameOut << " << FileNameOut <<

" " 內內 .\n"; .\n"; return 0;return 0;}}// ---// --- 函數 函數 Sort() Sort() 的定義的定義 ------------------int Sort(char X)int Sort(char X){ if ({ if (isupper(isupper(XX)))) return 0;return 0; else if (else if (islower(islower(XX)))) return 1;return 1;

3333/70/70

else if (else if (isdigit(isdigit(XX)))) return 2;return 2; else if (else if (isspace(isspace(XX)))) return 3;return 3; else if (else if (ispunct(ispunct(XX)))) return 4;return 4; elseelse return 5;return 5;} }

3434/70/70

操作結果 操作結果 (( 在顯示器上會看到下列訊在顯示器上會看到下列訊息:息: ) )

成功存於檔案 成功存於檔案 Conerted.txt Conerted.txt 內內 ..

檔案檔案 Original.txt Original.txt 的內容是:的內容是:I love you, certainly.I love you, certainly.

檔案檔案 Converted.txt Converted.txt 的內容是:的內容是:I LOVE YOU, CERTAINLY.I LOVE YOU, CERTAINLY.

3535/70/70

檔案資料流 檔案資料流 fstream fstream 的成員函數的成員函數表表 12.412.4    fstreamfstream 的成員函數的成員函數

成員函數名稱 用 途

get(Ch) 從輸入資料流讀取一個字元。

getline(S1,N,‘\n’)從輸入資料流讀取字元,並將其依序置於字串 S1中,直到已讀取( N-1 )個字元,或遇到字元‘ \n’ 。

peek()從輸入資料流中檢查下一個字元,但不將其從資料流中取出。

put(Ch) 將一個字元置於輸出資料流中

putback(Ch)在不影響檔案內容的情況下,對輸入資料流放回一個字元。

eof()如果讀取的動作超過 EOF(end-of-file ,檔案結尾 ) 則函數值為 true 。

ignore(N)跳過下面 N 個字元。如果不寫參數,而寫成 ignore() ,表示跳過下個字元。

3636/70/70

範例程式範例程式 RWFiles.cppRWFiles.cpp

從檔案 從檔案 Record.txt Record.txt 將字串資料和數值資料分將字串資料和數值資料分別讀到字串陣列別讀到字串陣列 Name Name 和數值陣列和數值陣列 ScoreScore 裏,裏,再單獨對再單獨對 ScoreScore 進行計算,最後把字串和數值進行計算,最後把字串和數值存到檔案 存到檔案 Saved.txt Saved.txt 裏。裏。

這個程式示範輸入資料流的成員函數這個程式示範輸入資料流的成員函數 peek()peek()的使用細節,它用來檢查即將讀入的字元是的使用細節,它用來檢查即將讀入的字元是否為 否為 EOFEOF 。。

3737/70/70

範例程式 檔案 範例程式 檔案 RWFiles.cppRWFiles.cpp

// RWFiles.cpp// RWFiles.cpp#include <iostream>#include <iostream>#include <iomanip>#include <iomanip>#include <fstream>#include <fstream>using namespace std;using namespace std;char* FileNameIn = "Record.txt";char* FileNameIn = "Record.txt";char* FileNameOut = "Saved.txt";char* FileNameOut = "Saved.txt";// ---// --- 主程式主程式 ------------------------------------------------int main()int main(){{ const int MaxNum = 40;const int MaxNum = 40; const int MaxSize = 20;const int MaxSize = 20; charchar NameName [[MaxNumMaxNum][][MaxSizeMaxSize];]; int int Score[Score[MaxNumMaxNum];];

3838/70/70

fstreamfstream FileInput(FileInput(FileNameInFileNameIn, ios::in);, ios::in); if (!if (!FileInputFileInput)) { cout << "{ cout << " 檔案檔案 : " << FileNameIn: " << FileNameIn << " << " 開啟失敗開啟失敗 !" << endl; exit(1);}!" << endl; exit(1);} fstream FileOutput(fstream FileOutput(FileNameOutFileNameOut, ios::out);, ios::out); if (!if (!FileOutputFileOutput)) { cout << "{ cout << " 檔案檔案 : " << FileNameOut: " << FileNameOut << " << " 存檔失敗存檔失敗 !" << endl; exit(1);} !" << endl; exit(1);} int int CountCount=0;=0; while (while (FileInput.peek()!= EOFFileInput.peek()!= EOF && (Count < MaxNum)) && (Count < MaxNum)) {{ FileInput >> Name[Count] >> Score[Count];FileInput >> Name[Count] >> Score[Count]; Count++;Count++; }}

3939/70/70

for (int i=0; i< Count; i++)for (int i=0; i< Count; i++) {{ Score[i] = Score[i]*0.8+20;Score[i] = Score[i]*0.8+20; FileOutputFileOutput << '(' << i+1 << ')' << '(' << i+1 << ')' << setw(12) << setw(12) << Name[i]<< Name[i] << " " << " " << setw(5) << setw(5) << Score[i] << Score[i] << <<

endl; endl; }} FileOutputFileOutput.close();.close(); FileInputFileInput.close();.close(); cout << "cout << " 成功存於檔案 成功存於檔案 " << FileNameOut" << FileNameOut << " << " 內內 ." << endl;." << endl; return 0;return 0;} }

4040/70/70

操作結果 操作結果 (( 在顯示器上會看到下列訊在顯示器上會看到下列訊息:息: ) )

成功存於檔案成功存於檔案 Saved.txt Saved.txt 內內 . .

檔案檔案 Record.txt Record.txt 的內容是:的內容是:王能治 王能治 8787李大為 李大為 9292蕭飛雪 蕭飛雪 7878張心怡 張心怡 8686

檔案檔案 Saved.txt Saved.txt 的內容是:的內容是:(1) (1) 王能治 王能治 8989(2) (2) 李大為 李大為 9393(3) (3) 蕭飛雪 蕭飛雪 8282(4) (4) 張心怡 張心怡 8888

4141/70/70

檔案內容的位置標記(檔案內容的位置標記( File Position MarkerFile Position Marker ))

位置標記使用「相對位置」的觀念:從某個位置位置標記使用「相對位置」的觀念:從某個位置當起點,再加上當起點,再加上偏移量偏移量 (offset) (offset) 以到達所要的位以到達所要的位置。置。

按照起點位置的不同,位置標記在使用上有下列按照起點位置的不同,位置標記在使用上有下列三種模式 三種模式 (modes of the file position marker)(modes of the file position marker) ::– ios::begios::beg 從檔案的開頭算起 從檔案的開頭算起 (beg(beg 為為 beginbegin 的縮寫的縮寫 ) ) – ios::curios::cur 從目前位置算起 從目前位置算起 (cur(cur 為為 currentcurrent 的縮的縮寫寫 ) )

– ios::endios::end 從檔案結尾算起 從檔案結尾算起 (end(end 為結尾的意思為結尾的意思 ))

4242/70/70

配合檔案內容的位置標記的成員函數配合檔案內容的位置標記的成員函數

表表 12.5.112.5.1  配合檔案內容的位置標記的成員函數 配合檔案內容的位置標記的成員函數

「位置標記」以及「偏移量」的資料型態必需是「位置標記」以及「偏移量」的資料型態必需是長整數長整數 (long in(long int)t) 。。

各成員函數名稱中的各成員函數名稱中的 gg 是是 getget ( ( 取得取得 )) ,而,而 pp 是是 putput ( ( 放入放入 ) ) 的簡寫。的簡寫。

成員函數 功 能

seekg (偏移量,模式) 在輸入檔案中,將位置標記依模式所規定的起點,移到偏移量所定的位置。

seekp (偏移量,模式) 在輸出檔案中,將位置標記依模式所規定的起點,移到偏移量所定的位置。

tellg() 從輸入檔案中,獲得位置標記目前所在的位置。

tellp() 從輸出檔案中,獲得位置標記目前所在的位置。

4343/70/70

位置標記的成員函數舉例位置標記的成員函數舉例

1. 1. FileOutput.seekp(5L, ios::cur);FileOutput.seekp(5L, ios::cur);:: 將位置標記在輸出檔案中從目前的位置往前移動將位置標記在輸出檔案中從目前的位置往前移動 55個字元的距離。個字元的距離。

2. 2. FileOutput.seekp(2L, ios::beg);FileOutput.seekp(2L, ios::beg); :: 將位置標記在輸出檔案中移到第將位置標記在輸出檔案中移到第 33 個字元的位置。個字元的位置。

3. 3. FileOutput.seekp(-5L, ios::end);FileOutput.seekp(-5L, ios::end); :: 將位置標記在輸出檔案中移到倒數第將位置標記在輸出檔案中移到倒數第 55 個字元的位個字元的位置。置。

4. 4. FileInput.seekg(0L, ios::beg);FileInput.seekg(0L, ios::beg); :: 將位置標記移到輸入檔案開頭的位置。將位置標記移到輸入檔案開頭的位置。

5. 5. FileInput.seekg(0L, ios::end);FileInput.seekg(0L, ios::end); :: 將位置標記移到輸入檔案結尾的位置。將位置標記移到輸入檔案結尾的位置。

4444/70/70

使用成員函數使用成員函數 tellg()tellg() 從檔案資料流中獲得從檔案資料流中獲得已開啟檔案中的字元數目已開啟檔案中的字元數目

例如:例如:ifstreamifstream FileInput (“Data.txt”); FileInput (“Data.txt”); // // 開啟檔案 開啟檔案 Data.tData.t

xtxt

longlong CharNum; CharNum;

FileInputFileInput.seekg(0L, ios::end);.seekg(0L, ios::end); // // 移到檔案結束的地移到檔案結束的地方方

CharNum = FileInput.tellg();CharNum = FileInput.tellg(); // // 獲得字元數目獲得字元數目

就可以得到 就可以得到 Data.txt Data.txt 中的字元數目,並將它儲存在長整數中的字元數目,並將它儲存在長整數 CharNumCharNum 中。中。

4545/70/70

使用使用 seekg() seekg() 以移動位置標記在已開啟的以移動位置標記在已開啟的檔案中游走檔案中游走

把位置標記先移到檔案結尾處,再逐一往前把位置標記先移到檔案結尾處,再逐一往前移動,把既有檔案中的字元次序顛倒過來:移動,把既有檔案中的字元次序顛倒過來:

longlong Offset; char Ch; Offset; char Ch;for (Offset=for (Offset=1L1L; Offset<= CharNum; Off; Offset<= CharNum; Offset++)set++)

{{FileInput.seekg(FileInput.seekg(-Offset, -Offset, ios::end)ios::end);;Ch = Ch = FileInput.get()FileInput.get();;FileOutputFileOutput << Ch; << Ch;

}}

4646/70/70

範例程式範例程式 FileReverse.cppFileReverse.cpp

我們將上述倒轉檔案內容的指令寫成完我們將上述倒轉檔案內容的指令寫成完整的範例程式。整的範例程式。

這個程式首先從檔案這個程式首先從檔案 Original.txt Original.txt 讀取讀取資料,將檔案中的字元次序顛倒過來後,資料,將檔案中的字元次序顛倒過來後,逐一存於檔案逐一存於檔案 Reversed.txtReversed.txt 中。中。

4747/70/70

範例程式 檔案 範例程式 檔案 FileReverse.cpp FileReverse.cpp

// FileReverse.cpp// FileReverse.cpp#include <iostream>#include <iostream>#include <iomanip>#include <iomanip>#include <fstream>#include <fstream>using namespace std;using namespace std;char* FileNameIn = "Original.txt";char* FileNameIn = "Original.txt";char* FileNameOut = "Reversed.txt";char* FileNameOut = "Reversed.txt";// ---// --- 主程式主程式 ------------------------------------------------int main()int main(){{ long CharNum, Offset;long CharNum, Offset; char Ch;char Ch; fstream FileInput(FileNameIn, ios::in); fstream FileInput(FileNameIn, ios::in);

4848/70/70

if (!FileInput)if (!FileInput) {{ cout << “cout << “ 檔案“ 檔案“ << FileNameIn<< FileNameIn   

<< " << " 開啟失敗開啟失敗 !" << endl; !" << endl; exit(1);exit(1); }} fstream FileOutput(FileNameOut, ios::out);fstream FileOutput(FileNameOut, ios::out); if (!FileOutput)if (!FileOutput) {{ cout << “cout << “ 檔案”檔案” << FileNameOut<< FileNameOut   

<< " << " 存檔失敗存檔失敗 !" << endl; !" << endl; exit(1);exit(1); }} cout << “cout << “ 檔案”檔案” << FileNameIn<< FileNameIn   

<< " << " 開啟成功開啟成功 " << endl;" << endl; FileInput.seekg(0L, ios::end); FileInput.seekg(0L, ios::end); // // 移到檔案結束的地方移到檔案結束的地方

4949/70/70

CharNum = FileInput.tellg(); CharNum = FileInput.tellg(); // // 獲得字元數目獲得字元數目 for (Offset=1L; Offset<= CharNum; Offset++)for (Offset=1L; Offset<= CharNum; Offset++) {{ FileInput.seekg(-Offset, ios::end);FileInput.seekg(-Offset, ios::end); Ch = FileInput.get();Ch = FileInput.get(); FileOutput << Ch;FileOutput << Ch; }} FileOutput.close(); FileOutput.close(); // // 關閉關閉 FileOuFileOu

tputtput FileInput.close(); FileInput.close(); // // 關閉關閉 FileIFileI

nputnput cout << "cout << " 倒轉檔案 倒轉檔案 " << FileNameIn" << FileNameIn << " << " 後的內容後的內容 \n\n 成功存於檔案 成功存於檔案 " " << FileNameOut << " << FileNameOut << " 內內 ." << endl;." << endl; return 0;return 0; } }

5050/70/70

範例程式範例程式 FileAccess.cppFileAccess.cpp

WriteString():WriteString(): 使用檔案以儲存字使用檔案以儲存字串的函數。串的函數。

WriteData():WriteData(): 使用檔案以儲存數字使用檔案以儲存數字的函數。的函數。

以字串為參數傳遞檔案名稱,參數以字串為參數傳遞檔案名稱,參數 ModModee 則是模式指示參數 則是模式指示參數 (mode indicator)(mode indicator) ,,當當 ModeMode 為為 11 時是時是 append (append ( 附加附加 )) ,, MoModede 為為 00 時是時是 replace (replace ( 取代取代 )) 。。

5151/70/70

範例程式範例程式 FileAccess.cpp: FileAccess.cpp: 函數函數 Add_Txt()Add_Txt()

在字串後面附加「在字串後面附加「 .txt.txt 」延伸檔名。」延伸檔名。 這個函數可以自動偵測做為檔案名稱的這個函數可以自動偵測做為檔案名稱的字串有沒有延伸檔名,並加以修正。字串有沒有延伸檔名,並加以修正。

這個函數使用了這個函數使用了 <cstring> <cstring> 裹面宣告的裹面宣告的函數函數 strcpy()strcpy() 。。

5252/70/70

範例程式 檔案 範例程式 檔案 FileAccess.cpp FileAccess.cpp

// FileAccess.cpp// FileAccess.cpp#include <iostream>#include <iostream>#include <iomanip>#include <iomanip>#include <fstream>#include <fstream>using namespace std;using namespace std;// --- // --- 函數的宣告 函數的宣告 ----------------------------------------------void Add_Txt(char *);void Add_Txt(char *);void WriteString (char *, char *, int Mode); void WriteString (char *, char *, int Mode); // Mode:(1 = append, 0 = replace)// Mode:(1 = append, 0 = replace) void WriteData (char *, float *, int, int Mode);void WriteData (char *, float *, int, int Mode);

// --- // --- 主程式 主程式 --------------------------------------------------------------------int main ()int main (){ {

5353/70/70

const DataSize = 12;const DataSize = 12; float float DataData [DataSize]; [DataSize]; char char FileNameFileName[20] = "SaveRecord";[20] = "SaveRecord"; char* char* S1 S1 = "A long time ago ..."; = "A long time ago ..."; Add_Txt(FileName);Add_Txt(FileName); for (int i = 0; i < DataSize; i++)for (int i = 0; i < DataSize; i++) DataData[i]= 3.8/float(1+i);[i]= 3.8/float(1+i); WriteString(FileNameWriteString(FileName, , S1S1, 0, 0);); WriteData(FileNameWriteData(FileName, , DataData, DataSize, 1, DataSize, 1);); return 0;return 0;}}

5454/70/70

// --- // --- 函數 函數 Add_Txt() Add_Txt() 的定義 的定義 ------------------------void void Add_Txt(Add_Txt(char *Fnamechar *Fname)){{ int i = 0;int i = 0; while ((Fname[i] != 0) && (Fname[i] != '.'))while ((Fname[i] != 0) && (Fname[i] != '.')) i++;i++; strcpy(Fname+i,".txt");strcpy(Fname+i,".txt");}}

5555/70/70

// --- // --- 函數 函數 WriteString () WriteString () 的定義 的定義 ----------------------------void WriteString (void WriteString (char *FileNameOut, char *String, int Mode)char *FileNameOut, char *String, int Mode){ { ofstream FileOutput;ofstream FileOutput; if (Mode)if (Mode) FileOutput.open( FileNameOut, ios::app);FileOutput.open( FileNameOut, ios::app); else else FileOutput.open( FileNameOut, ios::out);FileOutput.open( FileNameOut, ios::out); if (!FileOutput) if (!FileOutput) {cout << "{cout << " 檔案檔案 : " : " << FileNameOut << FileNameOut << " << " 存檔失敗存檔失敗 !"!" << endl; exit(1);} << endl; exit(1);} FileOutput << String;FileOutput << String; FileOutput.close();FileOutput.close(); cout << "cout << " 成功存於檔案 成功存於檔案 ""    << FileNameOut << FileNameOut

<< " << " 內內 ." << endl;." << endl;}}

5656/70/70

// --- // --- 函數 函數 WriteData () WriteData () 的定義 的定義 --------------------------------void WriteData (void WriteData (char *FileNameOut,char *FileNameOut, float *Data, int Size, int Modefloat *Data, int Size, int Mode)){ { ofstream FileOutput;ofstream FileOutput; if (Mode)if (Mode) FileOutput.open( FileNameOut, ios::app);FileOutput.open( FileNameOut, ios::app); else else FileOutput.open( FileNameOut, ios::out);FileOutput.open( FileNameOut, ios::out); if (!FileOutput) if (!FileOutput) {cout << "{cout << " 檔案檔案 : " : " << FileNameOut << FileNameOut << " << " 存檔失敗存檔失敗 !"!" << endl; exit(1);} << endl; exit(1);} FileOutput << "\nFileOutput << "\n 以下共有 以下共有 " << Size << " " << Size << " 組數據組數據 :\n";:\n"; for (int i = 0; i<Size; i++)for (int i = 0; i<Size; i++)    FileOutput << Data[i] << endl;FileOutput << Data[i] << endl; FileOutput.close();FileOutput.close(); cout << "cout << " 成功存於檔案 成功存於檔案 ""    << FileNameOut << FileNameOut

<< " << " 內內 ."<< endl;."<< endl;}}

5757/70/70

操作結果 操作結果 (( 在顯示器上會看到下列訊息在顯示器上會看到下列訊息 ) )

成功存於檔案 成功存於檔案 SaveRecord.txt SaveRecord.txt 內內 ..成功存於檔案 成功存於檔案 SaveRecord.txt SaveRecord.txt 內內 .. 檔案檔案 Record.txt Record.txt 的內容是:的內容是:

A long time ago ...A long time ago ...以下共有 以下共有 12 12 組數據:組數據:3.83.81.91.91.266671.266670.950.950.760.760.6333330.6333330.5428570.5428570.4750.4750.4222220.4222220.380.380.3454550.3454550.3166670.316667

5858/70/70

範例程式範例程式 Encoding.cpp Encoding.cpp 和和 Decoding.cppDecoding.cpp

改寫改寫 9.59.5 節程式節程式 EncodeText.cppEncodeText.cpp ,將它分成兩,將它分成兩個程式個程式 Encoding.cpp Encoding.cpp 和和 Decoding.cppDecoding.cpp ,分別,分別用來讀取檔案,將檔案內容編碼或解碼後,用來讀取檔案,將檔案內容編碼或解碼後,存於另外一個檔案中。存於另外一個檔案中。

在程式在程式 Encoding.cppEncoding.cpp 中,函數中,函數 Encode() Encode() 將檔將檔案內容編碼。案內容編碼。

在程式在程式 Decoding.cppDecoding.cpp 中,函數中,函數 Decode() Decode() 將檔將檔案內容解碼。案內容解碼。

5959/70/70

範例程式 檔案 範例程式 檔案 Encoding.cpp Encoding.cpp

// Encoding.cpp// Encoding.cpp#include <iostream>#include <iostream>#include <fstream>#include <fstream>using namespace std;using namespace std;// --- // --- 函數的宣告 函數的宣告 --------------------------------------------void GetString (char *FileNameIn, char *String);void GetString (char *FileNameIn, char *String);void Encode(char *String);void Encode(char *String);void WriteString (char *, char *, int Mode);void WriteString (char *, char *, int Mode);int main ()int main ()// --- // --- 主程式 主程式 ------------------------------------{{ char FileNameIn[20] = "OriginalText.txt";char FileNameIn[20] = "OriginalText.txt"; char FileNameOut[20] = "EncodedText.txt";char FileNameOut[20] = "EncodedText.txt"; const int MaxLength = 40;const int MaxLength = 40; char String[MaxLength];char String[MaxLength]; GetString(FileNameIn, String);GetString(FileNameIn, String);

6060/70/70

Encode(String);Encode(String); cout << "cout << " 編碼後的內容是編碼後的內容是 :\n" << String << endl;:\n" << String << endl; WriteString (FileNameOut, String, 0);WriteString (FileNameOut, String, 0); return 0;return 0;}}// --- // --- 函數 函數 GetString () GetString () 的定義 的定義 --------------------------------void GetString (char *FileNameIn,void GetString (char *FileNameIn, char *String)char *String){{ ifstream FileInput;ifstream FileInput; FileInput.open( FileNameIn );FileInput.open( FileNameIn ); if (!FileInput)if (!FileInput) {{ cout << "cout << " 檔案檔案 : " << FileNameIn: " << FileNameIn

<< " << " 開啟失敗開啟失敗 !\n"; exit(1);!\n"; exit(1); }}

6161/70/70

FileInput.getline(String,MaxLength);FileInput.getline(String,MaxLength); FileInput.close();FileInput.close(); cout << "cout << " 檔案檔案 : " << FileNameIn: " << FileNameIn << " << " 開啟成功開啟成功 ,\n,\n 下列是原有檔案內容下列是原有檔案內容 :\n":\n" << String << endl;<< String << endl;}}// --- // --- 函數 函數 Encode() Encode() 的定義 的定義 ----------------------------------------void Encode(char *String)void Encode(char *String){{ char Codes[28]= "DOJKZCTMYPAWHUQNBVGSRFXLIE ";char Codes[28]= "DOJKZCTMYPAWHUQNBVGSRFXLIE "; char ABC[28] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ ";char ABC[28] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ "; char abc[28] = "abcdefghijklmnopqrstuvwxyz ";char abc[28] = "abcdefghijklmnopqrstuvwxyz ";

6262/70/70

int i, j, Size=strlen(String);int i, j, Size=strlen(String); for(i=0; i< Size; i++)for(i=0; i< Size; i++) { { j=0;j=0; while( String[i]!=ABC[j]while( String[i]!=ABC[j] && String[i]!= a&& String[i]!= a

bc[j]bc[j]    && j<26 )&& j<26 ) j++;j++; String[i]=Codes[j];String[i]=Codes[j]; }} return;return;} } // --- // --- 函數 函數 WriteString () WriteString () 的定義 的定義 --------------------void void WriteString WriteString (char *FileNameOut,(char *FileNameOut, char *String, int Mode)char *String, int Mode)

6363/70/70

{{ ofstream FileOutput;ofstream FileOutput; if (Mode)if (Mode) FileOutput.open( FileNameOut, ios::app);FileOutput.open( FileNameOut, ios::app); elseelse FileOutput.open( FileNameOut, ios::out);FileOutput.open( FileNameOut, ios::out); if (!FileOutput)if (!FileOutput) {{ cout << “cout << “檔案檔案 : ”: ”   << FileNameOut<< FileNameOut   << “ << “ 存檔存檔

失敗 失敗 !\n"; exit(1);!\n"; exit(1); }} FileOutput << String;FileOutput << String; FileOutput.close();FileOutput.close(); cout << "cout << "成功存於檔案 成功存於檔案 ""   << FileNameOut << " << FileNameOut << "

內內 .\n";.\n"; return;return;} }

6464/70/70

範例程式 範例程式 22  檔案  檔案 Decoding.cpp Decoding.cpp

// Decoding.cpp// Decoding.cpp#include <iostream>#include <iostream>#include <fstream>#include <fstream>using namespace std;using namespace std;// --- // --- 函數 函數 GetString() GetString() 的宣告 的宣告 ----------------------------------void GetString (char *FileNameIn,char *String);void GetString (char *FileNameIn,char *String);// ---// --- 函數 函數 Decode() Decode() 的宣告的宣告 --------------------------------------------void Decode(char *String);void Decode(char *String);// --- // --- 函數 函數 WriteString () WriteString () 的宣告 的宣告 ----------------------------void WriteString (char *, char *, int Mode);void WriteString (char *, char *, int Mode);const int MaxLength = 40;const int MaxLength = 40;// === // === 主程式 主程式 ================================================================int main ()int main (){{

6565/70/70

char FileNameIn[20] = "EncodedText.txt";char FileNameIn[20] = "EncodedText.txt"; char FileNameOut[20] = "DecodedText.txt";char FileNameOut[20] = "DecodedText.txt"; char String[MaxLength];char String[MaxLength]; GetString(FileNameIn, String);GetString(FileNameIn, String); Decode(String);Decode(String); cout << "cout << "解碼後的內容是解碼後的內容是 :\n" << String << endl;:\n" << String << endl; WriteString (FileNameOut, String, 0); WriteString (FileNameOut, String, 0); return 0; return 0; }}// === // === 函數 函數 GetString () GetString () 的定義 的定義 ================================void void GetStringGetString (char *FileNameIn, char *String) (char *FileNameIn, char *String){{ ifstream FileInput;ifstream FileInput; FileInput.open( FileNameIn );FileInput.open( FileNameIn ); if (!FileInput)if (!FileInput) { cout<< “{ cout<< “檔案檔案 : ”<< FileNameIn << “ : ”<< FileNameIn << “ 開啟失 開啟失 敗敗 !\n";exit(1);}!\n";exit(1);}

FileInput.getline(String,MaxLength);FileInput.getline(String,MaxLength);

6666/70/70

FileInput.close();FileInput.close(); cout << "cout << "檔案檔案 : " << FileNameIn: " << FileNameIn << " << " 開啟成功開啟成功 ,\n,\n下列是原有檔案內容下列是原有檔案內容 :\n":\n" << String << endl;<< String << endl;}}// === // === 函數 函數 Decode() Decode() 的定義 的定義 ====================================void void DecodeDecode(char *String)(char *String){{ char Codes[28]= "DOJKZCTMYPAWHUQNBVGSRFXLIE ";char Codes[28]= "DOJKZCTMYPAWHUQNBVGSRFXLIE "; char ABC[28] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ ";char ABC[28] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ "; int i, j, Size = strlen(String);int i, j, Size = strlen(String); for (i=0; i<Size;i++)for (i=0; i<Size;i++) { { j=0;j=0; while (String[i]!=Codes[j] && j<26) j++;while (String[i]!=Codes[j] && j<26) j++; String[i]=ABC[j];String[i]=ABC[j]; }}

6767/70/70

}}// === // === 函數 函數 WriteString() WriteString() 的定義 的定義 ==========================void void WriteStringWriteString (char *FileNameOut, char *String, int M (char *FileNameOut, char *String, int M

ode)ode){{ ofstream FileOutput;ofstream FileOutput; if (Mode)if (Mode) FileOutput.open( FileNameOut, ios::app);FileOutput.open( FileNameOut, ios::app); elseelse FileOutput.open( FileNameOut, ios::out);FileOutput.open( FileNameOut, ios::out); if (!FileOutput)if (!FileOutput) { cout << “{ cout << “檔案檔案 : ” << FileNameOut << " : ” << FileNameOut << " 存檔存檔 失敗失敗 !\!\

n";n";   exit(1);}exit(1);} FileOutput << String;FileOutput << String; FileOutput.close();FileOutput.close(); cout << "cout << "成功存於檔案 成功存於檔案 " << FileNameOut << " " << FileNameOut << " 內內 ." << endl;." << endl;} }

6868/70/70

操作結果 操作結果

執行執行 Encoding.exeEncoding.exe 在顯示器上會看到下列訊息:在顯示器上會看到下列訊息:

執行執行 Decoding.exeDecoding.exe 在顯示器上會看到下列訊息:在顯示器上會看到下列訊息:

檔案: OriginalText.txt 開啟成功 ,下列是原有檔案內容:  I love you.編碼後的內容是:  Y WQFZ IQR成功存於檔案 EncodedText.txt 內 .

檔案: EncodedText.txt 開啟成功 ,下列是原有檔案內容:Y WQFZ IQR 解碼後的內容是:I LOVE YOU 成功存於檔案 DecodedText.txt 內 .

6969/70/70

操作結果操作結果

檔案檔案 OriginalText.txtOriginalText.txt 的內容是:的內容是:I LOVE YOUI LOVE YOU

檔案檔案 EncodedText.txtEncodedText.txt 的內容是:的內容是:Y WQFZ IQRY WQFZ IQR

檔案檔案 DecodedText.txtDecodedText.txt 的內容是:的內容是:I LOVE YOUI LOVE YOU