Python 入門指南 5.0

單元 35 - 存檔與載入

~~學習進度表~~

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

Encrypt → code
        ↓
         code.txt

完整程式請參考「範例程式碼」的 encrypt.pyencrypt_view.pyencrypt_controller.py

要直接儲存整個 Encrypt 物件到檔案也不是不可以,只是這麼一來就牽涉到物件還要序列化 (serialization) ,反倒因為密碼表是字串 (string) ,因此可以字串的方式來存檔。

儲存物件要利用標準程式庫 (standard library) 中的 pickle 模組 (module) 。

這是個相對簡單的方式,也就是說, Encrypt 類別 (class) 的 code 屬性 (attribute) 為密碼表字串,然後把這個字串儲存到一個固定檔名的純文字檔裡,就完成存檔的工作了。載入就讀取這個純文字檔,取得密碼表字串再重新建立 e ,並以密碼表字串當 __init__() 方法 (method) 的參數即可。

概念很簡單,可是跑程式時可能也會發生某些問題,例如 e 的初值為 None 的情況,如果使用者沒有按過新建就按下儲存,程式就會發生錯誤,因此這邊也要先進行條件 (condition) 檢查。

save_method() 方法的實作如下

57
59
61
62
64
66
68
    def save_method(self):
        if self.e == None:
            self.app.display_text["text"] = "無法儲存!"
        else:
            with open('./code.txt', 'w') as f:
                f.write(str(self.e)[6:])
            self.app.display_text["text"] = "完成存檔!"

這裡利用關鍵字 (keyword) withas 與內建函數 (function) open() 打開並且建立檔案物件 f ,需要兩個參數 (parameter) ,第一個參數為檔案路徑名稱,第二個參數則是檔案處理模式,這裡 'w' 表示寫入,若 code.txt 不存在就會建立檔案

64
            with open('./code.txt', 'w') as f:

f 取得檔案物件,接著寫入內容到檔案是利用檔案物件的 write() 方法,參數就是要寫入的字串內容

66
                f.write(str(self.e)[6:])

注意上面 self.eEncrypt 型態 (type) 的屬性,雖然重構 (refactoring) 後的 Encrypt 物件有 __str__() 方法可以直接回傳物件的字串形式,但是這裡涉及用序列 (sequence) 的索引值 (index) 取得子字串,因此 self.e[6:] 會被直譯器 (interpreter) 解讀是要用 Encrypt 類別使用索引值的方式,由於 Encrypt 類別並沒有設定用索引值的方式,因此會造成錯誤,所以要用內建函數 str() 先把 self.e 轉換成字串。

存檔工作結束後在訊息欄顯示檔案儲存成功訊息

68
            self.app.display_text["text"] = "完成存檔!"

載入則是讀取 code.txt 中的內容,因為檔案內容就是密碼表。不過載入時有可能發生檔案不存在的情況,就是使用者沒有按過儲存按鈕囉!這樣的話,相同目錄下不會存在 code.txt 檔案,所以這邊也是先做個檔案是否存在的條件檢查,程式如下

41
43
45
47
49
51
52
54
    def load_method(self):
        if os.path.exists("./code.txt"):
            with open('./code.txt', 'r') as f:
                code = f.readline()
            self.e = Encrypt(code)
            self.app.display_text["text"] = self.e
        else:
            self.app.display_text["text"] = "無法載入!"

這裡我們先用 os.path.exists() 判斷檔案是否存在

43
        if os.path.exists("./code.txt"):

因為用了標準程式庫裡的 os 模組,所以前面要先 import os

 8
import os

若不存在訊息欄就顯示載入失敗的訊息,若存在就進行載入工作,這裡是用檔案物件的 readline() 方法

47
                code = f.readline()

然後我們將 code 設定給 e 即可,這裡同樣 e 直接建立一個帶有參數的 Encrypt 物件

49
            self.e = Encrypt(code)

來執行看看囉!下面是存檔

相同目錄下就會新增 code.txt

開啟 code.txt 檢查密碼表是否有存入

下面是載入

功能 OK ,接下來就剩兩個方法要完成實作囉!

中英文術語對照
屬性attribute
類別class
條件condition
函數function
索引值index
直譯器interpreter
關鍵字keyword
方法method
模組module
物件object
參數parameter
重構refactoring
序列sequence
序列化serialization
標準程式庫standard library
字串string
型態type
重點整理
1. 存檔可儲存物件或字串,儲存物件須使用標準程式庫中的 pickle ,儲存字串可將字串直接寫入純文字檔案中。
2. 檔案處理利用關鍵字 withas 及內建函數 open() ,取得檔案物件後利用 write() 方法寫入資料,而 readline() 可讀取資料,由於是用關鍵字 with ,因此結束檔案處理工作後會自動調用 closed 關閉檔案物件。
3. os.path.exists() 可判斷指定路徑的檔案是否存在。
4. GUI 中任何一個動作都應該要顯示提示訊息給使用者,好讓使用者知道操作是否成功。
問題與討論
1. 為什麼儲存物件還要序列化,字串也是物件,可是字串卻不用?
2. 載入前如果檔案不存在會發生什麼情況?有其他的解決方式嗎?
練習
1. 寫一個程式 exercise3501.py ,利用 EntryButtonLabel 設計一個猜數字遊戲的 GUI 。 參考程式碼
2. 承上題,將新程式寫在 exercise3502.py 中,利用單元 27 練習 5Guess 類別,建立猜數字遊戲的遊戲流程。 參考程式碼
3. 承上題,將新程式寫在 exercise3503.py 中,加入一個 重新 按鈕,讓遊戲結束後可以再次重複進行。 參考程式碼
4. 承上題,將新程式寫在 exercise3504.py 中,改成全按鈕輸入的 GUI ,可加入一個 清空 輸入的按鈕。 參考程式碼
5. 承上題,將新程式寫在 exercise3505.py 中,利用按鈕的 config() 方法,將 state 設定為,這可以用來鎖住 0再一次 按鈕。 參考程式碼
6. 承上題,將新程式寫在 exercise3506.py 中,實作 清空 按鈕對應的程式碼。 參考程式碼
7. 承上題,將新程式寫在 exercise3507.py 中,實作數字按鈕對應的程式碼,按下數字按鈕後要鎖住該數字按鈕,並且顯示按下的數字到輸出欄,注意 清空 按鈕部分需要有相對應解鎖的程式碼。 參考程式碼
8. 承上題,將新程式寫在 exercise3508.py 中,加入 run_game() 方法,在使用者按下猜測數字數量之後進行遊戲結算。 參考程式碼
9. 承上題,將新程式寫在 exercise3509.py 中,實作 再一次 按鈕對應的程式碼。 參考程式碼
10. 承上題,將新程式寫在 exercise3510.py 中,增加在每一次猜中遊戲結束顯示平均猜測次數。 參考程式碼

上一頁 單元 34 - 整合 Encrypt 類別
回 Python 入門指南 5.0 首頁
下一頁 單元 36 - 完成版的 EncryptController
回 Python 教材首頁
回程式語言教材首頁