PyInstaller打包含JSON的Python程序遇问题,求单文件捆绑方案
解决PyInstaller打包含JSON依赖程序的单EXE问题及数据保护
一、解决单EXE无法找到JSON文件的问题
1. 修改代码中的路径获取逻辑
PyInstaller的--onefile模式会将所有资源解压到系统临时目录,因此不能直接使用相对路径,需要通过sys._MEIPASS获取临时目录路径。在代码中添加以下工具函数:
import sys import os def get_resource_path(relative_path): # 打包为EXE时,资源会放在sys._MEIPASS指向的临时目录 if hasattr(sys, '_MEIPASS'): return os.path.join(sys._MEIPASS, relative_path) # 源码运行时,使用脚本所在目录的相对路径 return os.path.join(os.path.dirname(__file__), relative_path)
之后用该函数获取JSON文件路径,替代原来的相对路径:
import json # 示例:获取data/topics.json的正确路径 topics_json_path = get_resource_path("data/topics.json") with open(topics_json_path, "r", encoding="utf-8") as f: topics_data = json.load(f)
2. 正确使用打包命令
执行打包时,通过--add-data参数将data目录(或单个JSON文件)嵌入EXE,Windows系统下路径分隔用分号:
# 打包整个data目录 pyinstaller --onefile --add-data "data;data/" your_script.py # 或打包单个JSON文件 pyinstaller --onefile --add-data "data/topics.json;data/" your_script.py
执行命令后生成的单EXE即可自动读取嵌入的JSON文件,无需手动复制data目录。
二、保护JSON中的敏感数据
如果JSON包含高分、正确答案等敏感内容,仅嵌入EXE仍可能被用户从临时目录提取查看,可采用以下两种方案:
方案1:将JSON转为Python字典直接嵌入代码
把JSON内容转换成Python字典格式,保存为单独的.py文件(比如game_data.py):
# game_data.py topics_data = { "topics": ["数学", "英语"], "high_scores": [100, 95], "correct_answers": {"q1": "A", "q2": "B"} }
在主脚本中直接导入使用:
from game_data import topics_data # 直接使用topics_data字典,无需读取JSON文件
这种方式下,数据会被编译进EXE,用户需要反编译才能获取内容,安全性远高于直接打包JSON。
方案2:对JSON内容加密后嵌入
如果需要更强的保护,可对JSON内容进行加密(例如AES加密),打包时将加密后的内容嵌入代码,运行时解密加载:
- 先对原始JSON文件加密(需先安装
pycryptodome库:pip install pycryptodome):
from Crypto.Cipher import AES from Crypto.Util.Padding import pad import base64 # 自定义密钥(需16/24/32位,示例用16位) key = b"your_secret_key_here" cipher = AES.new(key, AES.MODE_CBC) # 读取并加密JSON内容 with open("data/topics.json", "r", encoding="utf-8") as f: json_content = f.read().encode("utf-8") encrypted_data = cipher.encrypt(pad(json_content, AES.block_size)) # 保存初始化向量和加密后的数据(后续代码中需要用到) iv = base64.b64encode(cipher.iv).decode("utf-8") encrypted_str = base64.b64encode(encrypted_data).decode("utf-8") print(f"IV: {iv}") print(f"Encrypted data: {encrypted_str}")
- 在主脚本中添加解密逻辑:
from Crypto.Cipher import AES from Crypto.Util.Padding import unpad import base64 import json # 替换为刚才生成的IV和加密字符串 iv = base64.b64decode("生成的IV字符串") encrypted_str = base64.b64decode("生成的加密字符串") key = b"your_secret_key_here" # 解密并加载数据 cipher = AES.new(key, AES.MODE_CBC, iv) decrypted_content = unpad(cipher.decrypt(encrypted_str), AES.block_size).decode("utf-8") topics_data = json.loads(decrypted_content)
打包时PyInstaller会自动识别pycryptodome依赖,直接使用之前的打包命令即可。
内容的提问来源于stack exchange,提问作者sbird
相关产品推荐
相关产品推荐

