PyInstaller打包PyQt5应用后,执行特定功能时因找不到JSON配置文件崩溃的问题排查求助
我遇到了一个PyInstaller打包PyQt5应用后的问题,希望大家能帮忙排查:
我的项目目录结构如下:
--data -device_index.json -settings.json --reports --ui --tests --utilities -app.py
我以app.py为入口点,用以下PyInstaller命令打包:
pyinstaller --name measurement_automater --onefile --add-data "data/device_index.json;data" --add-data "data/settings.json;data" app.py
打包过程顺利,程序也能启动,但执行特定功能时会崩溃,报错:
FileNotFoundError: [Errno 2] No such file or directory: 'C:\alom_V3_24-01-main\dist\.\data\device_index.json'
我已经尝试用resource_path函数来处理路径,代码如下:
import os import sys 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.path.abspath(".") return os.path.join(base_path, relative_path)
在代码里我是这样调用的:
resource_path("data/device_index.json") # 或者 resource_path("data/settings.json")
我还试过把sys._MEIPASS换成sys._MEIPASS2,但还是出现同样的错误。
有没有人能帮我看看哪里出问题了?谢谢!
你好,我来帮你梳理一下可能的问题点和对应的解决方案:
1. 优化打包命令,完整包含资源目录
你当前是逐个添加JSON文件,这种方式容易出现路径匹配疏漏。建议直接打包整个data目录,修改PyInstaller命令为:
pyinstaller --name measurement_automater --onefile --add-data "data;data" app.py
这样整个data文件夹会被完整复制到打包后的临时目录,避免单个文件的路径配置错误。
2. 完善路径处理函数,适配系统分隔符
Windows系统下路径分隔符是\,虽然Python的os.path.join能自动兼容,但标准化路径可以彻底避免潜在问题。修改resource_path函数如下:
import os import sys def resource_path(relative_path): """ Get absolute path to resource, works for dev and for PyInstaller """ try: base_path = sys._MEIPASS except Exception: base_path = os.path.abspath(".") # 标准化路径,适配不同系统的分隔符规则 relative_path = os.path.normpath(relative_path) return os.path.join(base_path, relative_path)
3. 全面排查代码中的路径引用
务必确保所有读取这两个JSON文件的地方都使用了resource_path函数,有没有漏写的情况?比如直接用open("data/device_index.json")而没有包裹resource_path,这种情况在开发环境能正常运行,但打包后就会找不到文件。
4. 验证临时目录的文件结构
可以在resource_path函数里添加打印语句,查看打包后临时目录的真实情况:
def resource_path(relative_path): try: base_path = sys._MEIPASS # 打印临时目录路径,方便手动排查 print(f"PyInstaller临时目录路径: {base_path}") # 打印data目录下的文件列表,确认资源是否存在 data_dir = os.path.join(base_path, 'data') print(f"临时data目录下的文件: {os.listdir(data_dir) if os.path.exists(data_dir) else 'data目录不存在'}") except Exception: base_path = os.path.abspath(".") relative_path = os.path.normpath(relative_path) return os.path.join(base_path, relative_path)
运行打包后的exe,控制台会输出临时目录的位置,你可以手动打开这个目录,确认data文件夹里是否存在目标JSON文件。
5. 检查Windows环境下的命令行语法
如果你是用PowerShell执行打包命令,需要注意分号;是PowerShell的命令分隔符,这时候需要用单引号包裹--add-data的参数,或者转义分号:
# 用单引号包裹参数的写法 pyinstaller --name measurement_automater --onefile --add-data 'data;data' app.py # 或者转义分号 pyinstaller --name measurement_automater --onefile --add-data "data`;data" app.py
之前的命令可能因为PowerShell的解析规则,导致资源文件没有被正确打包进去。
按照上面的步骤逐一排查,应该能定位并解决问题。
备注:内容来源于stack exchange,提问作者Mr.LoudMouth

