2009-10-02 90 views
3

我有一個Python應用程序。它加載配置文件(以及各種其他文件)由 做的東西,如:py2exe和文件系統

_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 
CONFIG_DIR = os.path.join(_path, 'conf') 

這工作得很好。然而,當我打包帶py2exe應用,不好的事情發生了:

File "proj\config.pyc", line 8, in <module> 
WindowsError: [Error 3] The system cannot find the path specified: 'C:\\proj\ 
\dist\\library.zip\\conf' 

顯然,這是一個無效的路徑...什麼是這樣做的更強大的方法嗎?我不想 想要在程序中指定絕對路徑,因爲它可以放在不同的 文件夾中。我應該只是說「如果它說文件夾的名稱是'library.zip',然後去 一級更低的'dist'文件夾」?

請注意,我有相當嵌套的目錄層次結構...例如,我有一個 模塊gui.utils.images,存儲在「GUI/utils的/ images.py」,並使用其路徑 訪問「例如,gui/images/ok.png「。現在py2exe版本 會嘗試訪問「proj/dist/library.zip/gui/images/ok.png」,或者其他的東西, ,這些都不起作用。

回答

2

您如何看待所有包含文件的相對路徑?我想應該可以使用sys.path.append(".." + os.path.sep + "images")作爲關於ok.png的例子,那麼你可以只使用open("ok.png", "rb")。使用相對路徑應該解決由py2exe生成的library.zip文件的問題,至少這是它對我的作用。

+0

嗯我會給那一槍。即時通訊編寫一個函數getAbsPath()採用相對路徑,只是返回正確的東西打開。它會檢測它是否在library.zip中,如果是,它會轉到另一個dir上,而不是實際的fs – Claudiu 2009-10-02 20:41:26

+0

您也可以嘗試將包含文件放到包目錄中,因爲'__init__ .py的'__path__'屬性將存儲'__init __。py'腳本的路徑。 – fucx 2009-10-03 07:52:29

10

通常的方法在做這樣的事情(如果我理解正確)是這樣的:

  1. 檢查sys.frozen,這py2exe contrives設定,使用類似GETATTR(SYS,「凍結」, 「」)
  2. 如果沒有設置,使用通常的方法,因爲你是從源代碼
  3. 如果它被設置在運行,檢查sys.executable因爲這將指向你在.exe文件(而不是到蟒蛇.exe是,這是它通常指向的)。使用類似os.path.dirname(sys.executable),然後加入與您的相對路徑找到的子文件夾等

例子:

frozen = getattr(sys, 'frozen', '') 

if not frozen: 
    # not frozen: in regular python interpreter 
    approot = os.path.dirname(__file__) 

elif frozen in ('dll', 'console_exe', 'windows_exe'): 
    # py2exe: 
    approot = os.path.dirname(sys.executable) 

elif frozen in ('macosx_app',): 
    # py2app: 
    # Notes on how to find stuff on MAC, by an expert (Bob Ippolito): 
    # http://mail.python.org/pipermail/pythonmac-sig/2004-November/012121.html 
    approot = os.environ['RESOURCEPATH'] 

或其某種變種......後者處理py2app的使用。如果需要,您可以將其擴展到其他構建器。

2

從py2exe應用程序使用os.path.dirname(os.path.abspath(sys.argv [0])),它將以相同的方式從python腳本運行(這樣您就可以在不創建exe的情況下進行測試每次)和exe文件。

這可以比使用相對路徑好得多,因爲您不必擔心應用程序(.py或.exe)從哪裏運行。

2

這是我的解決方案(在Windows,Linux和Mac上測試)。如果應用程序或Python腳本通過符號鏈接啓動,它也可以工作。

# Get if frozen 
is_frozen = bool(getattr(sys, 'frozen', None)) 

# Get path variable 
path = sys.path if is_frozen else sys.argv 

# Get nonempty first element or raise error 
if path and path[0]: 
    apppath = path[0] 
elif is_frozen(): 
    raise RuntimeError('Cannot determine app path because sys.path[0] is empty.') 
else: 
    raise RuntimeError('Cannot determine app path in interpreter mode.') 

# Make absolute (eliminate symbolic links) 
apppath = os.path.abspath(os.path.realpath(apppath)) 

# Split and return 
appdir, appname = os.path.split(apppath) 
0

我在windows中使用下面的技巧。
當程序被凍結在py2exe'可執行文件'中時(例如my_application。exe),dirname(__file__)返回您的主python腳本正在運行的文件夾。 奇怪的是,該文件夾不是包含my_application.exemy_application.exe本身的文件夾。
請注意,my_application.exe不是一個二進制文件,而是一個壓縮文件夾(可以將其解壓縮),它包含python庫和您的編譯腳本。
這就是爲什麼您的__file__os.path.dirname實際上是my_application.exe

因此,這個代碼給您的配置文件或圖像的根目錄下(在冷凍應用的情況下,含有py2exe可執行文件的文件夾,否則在你的Python腳本運行其中的文件夾):

dirname = os.path.dirname(__file__) 
if dirname.endswith('.exe'): 
    dirname = os.path.split(dirname)[0] 

顯然,您可以使用更一般的便攜式方法來檢測文件是否被凍結,因爲其他答案顯示而不是endswith方法。