Pyinstaller应用程序正在访问txt文件,但没有写入它们(在应用程序编译之前工作)

时间:2016-12-10 07:14:46

标签: python pyinstaller

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)

2 个答案:

答案 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