Java 入門指南
單元 24 - 存檔與載入
存檔要儲存什麼呢?直覺告訴我們應該要儲存 Encrypt 物件 (object) ,不過可以簡單點,儲存密碼表就可以了
要直接儲存整個 Encrypt 物件 (object) 到檔案也不是不可以,只是這麼一來就牽涉到物件還要序列化 (serialization) ,反倒因為密碼表是字串 (string) ,因此可以字串的方式來存檔。字串是很常用的資料型態,因此 API 中提供相對簡單的方式來處理字串,像是字串可以直接儲存到副檔名 .txt 的純文字檔案中,也能夠直接從純文字檔案讀進程式中。
程式執行時,所有跟程式相關的各種物件都是存在於電腦記憶體中,至於存檔是要以檔案格式儲存到硬碟或其他媒體裡,讀檔則是從硬碟或其他媒體將檔案內容放回記憶體。
檔案功能要先引入如下 API 中相關的類別 (class)
import java.io.File;
import java.io.FileWriter;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.IOException;
完整程式請參考「範例程式篇」的 FXMLDocumentController.java 。
以下是存檔 saveCode() 方法 (method) 的實作
@FXML
private void saveMethod(ActionEvent event) {
try {
if (e == null) {
display.setText("沒有密碼物件!");
}
else {
File f = new File("code.txt");
FileWriter fw = new FileWriter(f);
fw.write(String.valueOf(e.code));
fw.close();
}
display.setText("儲存成功!");
}
catch (IOException ex) {
display.setText("儲存失敗!");
}
finally {
output.setText("存檔之後...");
}
}
saveCode() 方法內容是 try-catch-finally 複合陳述
try {
if (e == null) {
display.setText("沒有密碼物件!");
}
else {
File f = new File("code.txt");
FileWriter fw = new FileWriter(f);
fw.write(String.valueOf(e.code));
fw.close();
}
display.setText("儲存成功!");
}
catch (IOException ex) {
display.setText("儲存失敗!");
}
finally {
output.setText("存檔之後...");
}
try-catch-finally 是進行例外處理 (exception handling) ,由於 API 中檔案處理的相關程式碼會拋出例外 (exception) ,因此要把檔案處理的程式碼放在 try 底下的大括弧, catch 則是針對例外發生後,進行處理的部份,例如
catch (IOException ex) {
display.setText("儲存失敗!");
}
所謂例外就是執行期間錯誤 (run-time error) , Java 利用例外處理來捕捉執行期間錯誤,然後在程式中做即期處理,讓程式能順利繼續執行。
這裡是假設以上 try 的部分如果發生了型態為 IOException 的例外,就在 display 顯示「儲存失敗!」的提示訊息。
繼續看到 try 底下大括弧的內容,也就是實際處理存檔的部分
if (e == null) {
display.setText("沒有密碼物件!");
}
else {
File f = new File("code.txt");
FileWriter fw = new FileWriter(f);
fw.write(String.valueOf(e.code));
fw.close();
}
display.setText("儲存成功!");
這裡是用一層的 if-else ,如果使用者沒按過新鍵按鈕,也就沒有編碼物件,物然無法存檔,因此就直接顯示無法存檔的提示訊息,反之有編碼物件,就盡如存檔程序
File f = new File("code.txt");
FileWriter fw = new FileWriter(f);
fw.write(e.code);
fw.close();
存檔先建立 File 型態的物件變數 f , File() 需要以檔案路徑當參數,這裡是用 code.txt ,也就是純文字格式的檔案,接下來建立 FileWriter 型態的物件變數 fw , FileWriter() 需要 File 物件當參數,這裡直接用剛剛建立的變數 f ,然後利用 FileWriter 的 write() 方法,以屬性 e 的 code 屬性當參數,由於 code 是字串,因此可以直接當 write() 方法的參數,這樣就可以把密碼表存入 code.txt 中了。注意,最後 fw 要呼叫 close() 方法關閉檔案處理物件。
繼續看到載入方法 loadMethod()
@FXML
private void loadMethod(ActionEvent event) {
try {
FileReader fr = new FileReader("code.txt");
BufferedReader r = new BufferedReader(fr);
String ms = r.readLine();
e = new Encrypt(ms);
fr.close();
display.setText("載入成功!");
}
catch (IOException ex) {
display.setText("載入失敗!");
}
finally {
output.setText("載入之後...");
}
}
這裡直接看到 try 底下大括弧的部分
FileReader fr = new FileReader("code.txt");
BufferedReader r = new BufferedReader(fr);
String ms = r.readLine();
e = new Encrypt(ms);
fr.close();
display.setText("載入成功!");
讀取的部分是用 FileReader 型態的變數 fr ,同樣 FileReader() 要以檔案路徑當參數,然後建立 BufferedReader 型態的變數 r ,以 fr 當參數,再來用 BufferedReader 的 readLine() 取得 code.txt 的第一行內容,由於密碼表就是儲存在 code.txt 的第一行,因此這裡就是讀取密碼表,然後把密碼表當作 Encrypt() 的參數,新建立的 Encrypt 物件指派給屬性 e ,最後檔案處理完, fr 要呼叫 close() 方法關閉檔案處理物件,然後在 display 顯示提示訊息。
File 物件可以建立檔案,因此存檔時用 File 物件,至於 FileReader 物件是專門讀取檔案內容,如果檔案不存在就會發起例外。
下面來試看看囉!先進行編碼
然後進行存檔
換成新的編碼結果
然後載入
重新編碼
載入重新編碼無誤,下一個單元繼續實作剩下的清空與複製兩個按鈕。
相關教學影片
中英文術語對照 | |
---|---|
class | 類別 |
exception handling | 例外處理 |
exception | 例外 |
method | 方法 |
object | 物件 |
run-time error | 執行期間錯誤 |
serialization | 序列化 |
string | 字串 |
重點整理 |
---|
1. 存檔直接把密碼表儲存在純文字檔案 code.txt 中。 |
2. 存檔、載入是利用 Java API 中的相關類別,由於該類別會拋出例外,因此要做例外處理。 |
3. 例外處理是預防可能會發生的執行期間錯誤,如果發生了執行期間錯誤,程式要進行哪些工作。 |
問題與討論 |
---|
1. 如果沒有 Encrypt 物件就進行存檔會怎麼樣呢? |
2. 為什麼載入前要先檢查檔案存不存在? |
練習 |
---|
1. 承接上一個單元的 HelloDemo 專案,在 handleButtonAction() 方法中計算 count 除以 2 的餘數是否為 0 ,如果是 0 ,把 label 的文字設定為 "你好" ,反之設定為 "世界" 。 |
2. 承接上一個單元的 GuessGameDemo 專案,替十一個按鈕設置各自以 @FXML 連結的方法,每個按鈕可以先做簡單的事情,例如在命令列顯示按了哪個按鈕。 |
3. 承上題,在跟開始遊戲連動的方法加入以下內容
其中按鈕呼叫 setDisable(false) ,這是把按鈕設定為不可用。 |