Java 入門指南

單元 24 - 存檔與載入

~~學習進度表~~

存檔要儲存什麼呢?直覺告訴我們應該要儲存 Encrypt 物件 (object) ,不過可以簡單點,儲存密碼表就可以了

Encrypt? code?

要直接儲存整個 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 型態的物件變數 fFile() 需要以檔案路徑當參數,這裡是用 code.txt ,也就是純文字格式的檔案,接下來建立 FileWriter 型態的物件變數 fwFileWriter() 需要 File 物件當參數,這裡直接用剛剛建立的變數 f ,然後利用 FileWriterwrite() 方法,以屬性 ecode 屬性當參數,由於 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 當參數,再來用 BufferedReaderreadLine() 取得 code.txt 的第一行內容,由於密碼表就是儲存在 code.txt 的第一行,因此這裡就是讀取密碼表,然後把密碼表當作 Encrypt() 的參數,新建立的 Encrypt 物件指派給屬性 e ,最後檔案處理完, fr 要呼叫 close() 方法關閉檔案處理物件,然後在 display 顯示提示訊息。

File 物件可以建立檔案,因此存檔時用 File 物件,至於 FileReader 物件是專門讀取檔案內容,如果檔案不存在就會發起例外。

下面來試看看囉!先進行編碼

然後進行存檔

換成新的編碼結果

然後載入

重新編碼

載入重新編碼無誤,下一個單元繼續實作剩下的清空複製兩個按鈕。

相關教學影片

上一頁 單元 23 - 整合 Encrypt 類別
回 Java 入門指南首頁
下一頁 單元 25 - 完成版的 JavaFX 專案
回 Java 教材首頁
回程式語言教材首頁
中英文術語對照
class類別
exception handling例外處理
exception例外
method方法
object物件
run-time error執行期間錯誤
serialization序列化
string字串
參考資料
1. JavaFX 8.0: Introduction to FXML
2. JavaFX: Working with JavaFX UI Components - Label
3. JavaFX: Working with JavaFX UI Components - Button
4. JavaFX: Working with JavaFX UI Components - Text Field
5. Java Platform 8: File
6. Java Platform 8: FileWriter
7. Java Platform 8: FileReader
8. Java Platform 8: BufferedReader
9. Java Platform 8: IOException
重點整理
1. 存檔直接把密碼表儲存在純文字檔案 code.txt 中。
2. 存檔、載入是利用 Java API 中的相關類別,由於該類別會拋出例外,因此要做例外處理。
3. 例外處理是預防可能會發生的執行期間錯誤,如果發生了執行期間錯誤,程式要進行哪些工作。
問題與討論
1. 如果沒有 Encrypt 物件就進行存檔會怎麼樣呢?
2. 為什麼載入前要先檢查檔案存不存在?
練習
1. 承接上一個單元的 HelloDemo 專案,在 handleButtonAction() 方法中計算 count 除以 2 的餘數是否為 0 ,如果是 0 ,把 label 的文字設定為 "你好" ,反之設定為 "世界"
2. 承接上一個單元的 GuessGameDemo 專案,替十一個按鈕設置各自以 @FXML 連結的方法,每個按鈕可以先做簡單的事情,例如在命令列顯示按了哪個按鈕。
3. 承上題,在跟開始遊戲連動的方法加入以下內容
display.clear();
count = 0;
user_input = "";
game = new Guess();
button1.setDisable(false);
button2.setDisable(false);
button3.setDisable(false);
button4.setDisable(false);
button5.setDisable(false);
button6.setDisable(false);
button7.setDisable(false);
button8.setDisable(false);
button9.setDisable(false);
button0.setDisable(false);
display.appendText("遊戲開始\n");
其中按鈕呼叫 setDisable(false) ,這是把按鈕設定為不可用。