PyInstaller可以協助我們將Python程式包裝成單一的執行檔案。同時也可以協助我們程式所需的資料檔案一併包裝起來。資料檔案一般我們都是在PyInstaller的spec檔案中加入如下的敘述:
a.datas += [('images/my.png', '/src/images/my.png', 'DATA'), ('images/other.png', '/src/images/other.png', 'DATA'), ('db/main.db', 'main.db', 'DATA')]
但是如果你在程式中寫上,像是
fd = file('db/main.db', 'rb')
或是
fd = file('main.db', 'rb')
不管是哪一個,你只有在未包裝前可以正確的開啟檔案,一旦包裝起來再執行就無法正確取得檔案了。其原因在於你的包裝好的執行檔案在執行時的時候,所有的東西會被解到一個暫時的目錄去,這個目錄你無法在寫程式的時候就確定好。所以就無法直接取得檔案。
還好網路上有人回答了這個問題。作法就是透過PyInstaller所提供的資訊來得到當時的目錄。下面這個function可以很方便的幫助你在程式中取得資料的檔案的路徑。
def rc(rel_path): """Return full path of resource according to rel_path.""" if not hasattr(sys, '_MEIPASS'): # for elder PyInstaller. rc_path = os.environ.get("_MEIPASS2", os.getcwd()) else: rc_path = getattr(sys, '_MEIPASS', os.getcwd()) return os.path.join(rc_path, rel_path) dbfile = rc('db/main.db') ...
要注意的是,這些資料檔案應該只作為讀取的用途。寫入資料到裡面去是沒有用的。因為下一次程式執行的時候它就不見了。
Reference:
留言