如何取得利用PyInstaller所包入的資料檔案

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')

不管是哪一個,你只有在未包裝前可以正確的開啟檔案,一旦包裝起來再執行就無法正確取得檔案了。其原因在於你的包裝好的執行檔案在執行時的時候,所有的東西會被解到一個暫時的目錄去,這個目錄你無法在寫程式的時候就確定好。所以就無法直接取得檔案。

[][1]

還好網路上有人回答了這個問題。作法就是透過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:

  1. Bundling data files with PyInstaller (–onefile)

[1]:

comments powered by Disqus