【问题标题】:Pyinstaller app is accessing txt files, but not writing to them (works before app compilation)Pyinstaller 应用程序正在访问 txt 文件,但没有写入它们(在应用程序编译之前工作)
【发布时间】:2017-04-25 16:23:01
【问题描述】:

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)

【问题讨论】:

  • f2.write('update') 如果不关闭文件,您将丢失数据。退出应用前需要f2.close()
  • 相信使用with时会自动调用close()方法@
  • 如果您的设置文件为空,则否!
  • 另一点,您如何知道退出时“一切都已完成”?退出前需要验证一切。
  • 它正在编写它们...但它不会重新捆绑您的应用程序,因此下次运行它时它将与原始应用程序一起扩展您的捆绑包...尝试将您的设置文件保存在 @987654331 之类的地方@

标签: python pyinstaller


【解决方案1】:

如果您在 Windows 上,_MEIPASS 会返回路径的“短”名称,以防路径的任何组件长度超过 8 个字符。因此,要测试这是否是问题所在,请尝试将其设置为 one-folder 冻结应用,然后将其移动到简单而简短的路径中:例如 C:/test

如果这是问题所在,您可以通过使用以下方法检索长路径来解决该问题:

if hasattr(sys, '_MEIPASS'):
    import win32api
    sys_meipass = win32api.GetLongPathName(sys._MEIPASS)

【讨论】:

    【解决方案2】:

    我想分享我的解决方案,它同时解决了一般相对路径的许多问题(请参阅函数 __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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-03
      • 2019-09-19
      • 1970-01-01
      • 1970-01-01
      • 2019-02-15
      • 1970-01-01
      相关资源
      最近更新 更多