settings.txt在编译的单个文件应用程序中存储和访问,但它没有被写入。当文件与脚本位于同一目录时,这在Pyinstaller编译之前有效。
该应用程序是从终端编译的:
pyinstaller script.spec script.py --windowed --onefile
a.datas
在规范文件中设置为:
a.datas += [(‘settings.txt’,’/path/to/settings.txt’, "DATA”)]
并在应用程序中正确读取文件:
with open(resource_path('settings.txt'), 'r') as f2
但是,尝试覆盖文件时文件未更新:
def OnExit(self, event):
with open(resource_path('settings.txt'), 'w') as f2:
f2.write('update')
self.Destroy()
resource_path
定义为:
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
base_path = sys._MEIPASS
except Exception:
base_path = os.environ.get("_MEIPASS2", os.path.abspath("."))
return os.path.join(base_path, relative_path)
答案 0 :(得分:1)
如果您使用的是Windows,_MEIPASS
会返回"短"路径的名称,如果它的任何组件长度超过8个字符。因此,要测试这是问题所在,请尝试将其设为one-folder
冻结的应用,然后将其移至简单而短的路径中:例如C:/test
。
如果这是问题,您可以通过使用以下内容检索长路径来解决问题:
if hasattr(sys, '_MEIPASS'):
import win32api
sys_meipass = win32api.GetLongPathName(sys._MEIPASS)
答案 1 :(得分:0)
我想分享我的解决方案,它同时解决了一般相对路径的许多问题(请参阅函数 __doc__string)。
我有一个名为 top_level_locator.py
的模块,带有修改后的函数 module_path
,如其他答案中所示,它采用 relative_path
。
在其他 .py
文件中的使用:
from top_level_locator import module_path
resource_location = module_path(relative_path = 'resource.ext')
import sys
from pathlib import Path
from inspect import getsourcefile
def module_path(relative_path):
"""
Combine top level path location, in this project app.py folder because it serves as main/entry_point, with user relative path.
NOTE: top_level_locator.py should be in same folder as entry_point.py(/main.py) script
- TEST this with executable
- TEST this without executable
NOTE: care with use of __file__ as it comes with unwarranted side effects when:
- running from IDLE (Python shell), no __file__ attribute
- freezers, e.g. py2exe & pyinstaller do not have __file__ attribute!
NOTE: care with use of sys.argv[0]
- unexpected result when you want current module path and get path where script/executable was run from!
NOTE: care with use of sys.executable
- if non-frozen application/module/script: python/path/python.exe
- else : standalone_application_executable_name.exe
"""
# 0 if this module next to your_entry_point.py (main.py) else += 1 for every directory deeper
n_deep = 1
print('sys.executable:', sys.executable)
print(' sys.argv[0]:', Path(sys.argv[0]).parents[n_deep].absolute() / sys.argv[0])
print(' __file__:', __file__)
print(' getsourcefile:', Path(getsourcefile(lambda:0)).parents[n_deep].absolute())
if hasattr(sys, "frozen"):
# retreive possible longpath if needed from _MEIPASS: import win32api;
# sys_meipass = win32api.GetLongPathName(sys._MEIPASS)
base_path = getattr(sys, '_MEIPASS', Path(sys.executable).parent)
print(' _MEIPASS:', base_path)
return Path(base_path).joinpath(relative_path)
return Path(getsourcefile(lambda:0)).parents[n_deep].absolute().joinpath(relative_path)
if __name__ == '__main__':
module_path()
在非冻结应用程序中,输出将(应该)如下:
sys.executable: C:\Users\<usr_name>\AppData\Local\Programs\Python\Python37\python.exe
sys.argv[0]: c:\Users\<usr_name>\Desktop\<project_name>\<project_code_folder>\app.py
__file__: c:\Users\<usr_name>\Desktop\<project_name>\<project_code_folder>\utils\top_level_locator.py
getsourcefile: c:\Users\<usr_name>\Desktop\<project_name>\<project_code_folder>
在冻结的应用程序中:
sys.executable: C:\Users\<usr_name>\Desktop\<project_name>\dist\app.exe
sys.argv[0]: C:\Users\<usr_name>\Desktop\<project_name>\dist\app.exe
__file__: C:\Users\<usr_name>\AppData\Local\Temp\_MEI155562\utils\top_level_locator.pyc
getsourcefile: C:\Users\<usr_name>\Desktop\<project_name>
_MEIPASS: C:\Users\<usr_name>\AppData\Local\Temp\_MEI155562