You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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加密),打包时将加密后的内容嵌入代码,运行时解密加载:

  1. 先对原始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}")
  1. 在主脚本中添加解密逻辑:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 02:22:47