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

QT+Python程序转exe/安装包后数据丢失问题求助

解决方案

核心思路:分离只读资源与可写数据目录

程序运行时,只读资源(如初始JSON模板、图片、字体) 放在PyInstaller打包的资源目录(_MEIPASS),而可写数据需要存到用户有写入权限的系统标准目录,比如:

  • Windows: C:\Users\<用户名>\AppData\Roaming\SmartTank
  • macOS: ~/Library/Application Support/SmartTank
  • Linux: ~/.config/SmartTank

步骤1:修改路径处理逻辑

新增两个方法,分别处理只读资源路径和可写数据路径:

import sys
import os
import json
import shutil
from pathlib import Path

class YourMainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        # 初始化应用数据目录并确保目录存在
        self.app_data_dir = self.get_app_data_dir()
        os.makedirs(self.app_data_dir, exist_ok=True)

    def resource_path(self, relative_path):
        """获取只读资源的绝对路径(兼容开发环境与PyInstaller打包)"""
        try:
            base_path = sys._MEIPASS
        except Exception:
            base_path = os.path.abspath(".")
        return os.path.join(base_path, relative_path)

    def get_app_data_dir(self):
        """获取用户可写的应用数据目录,跨平台兼容"""
        if sys.platform == 'win32':
            return os.path.join(os.environ['APPDATA'], 'SmartTank')
        elif sys.platform == 'darwin':
            return os.path.join(os.path.expanduser('~'), 'Library', 'Application Support', 'SmartTank')
        else:
            return os.path.join(os.path.expanduser('~'), '.config', 'SmartTank')

    def get_data_file_path(self, filename):
        """获取可写数据文件路径,自动复制初始模板(若不存在)"""
        data_file = os.path.join(self.app_data_dir, filename)
        # 若数据文件不存在,从只读资源目录复制初始模板
        if not os.path.exists(data_file):
            template_file = self.resource_path(f'database/{filename}')
            if os.path.exists(template_file):
                shutil.copy(template_file, data_file)
            else:
                # 无初始模板时创建空数据结构
                if filename == 'data_nomor.json':
                    with open(data_file, 'w') as f:
                        json.dump({"nomor": []}, f)
        return data_file

步骤2:修改数据读写逻辑

以save_data_nomor为例,替换原路径调用为新的可写路径方法:

def save_data_nomor(self):
    new_number = self.ui.inputNomor.text().strip()
    if new_number == "":
        print("Number cannot be empty.")
        return

    # 获取可写数据文件路径
    file_path = self.get_data_file_path('data_nomor.json')
    try:
        with open(file_path, 'r') as file:
            data_nomor = json.load(file)
    except Exception as e:
        print(f"Error reading JSON file: {e}")
        data_nomor = {"nomor": []}

    if new_number not in data_nomor["nomor"]:
        data_nomor["nomor"].append(new_number)

    try:
        with open(file_path, 'w') as file:
            json.dump(data_nomor, file, indent=4)
        print(f"Number '{new_number}' successfully saved.")
    except Exception as e:
        print(f"Error saving JSON file: {e}")
    
    self.ui.inputNomor.clear()

步骤3:调整PyInstaller打包命令

单文件/非单文件打包命令保持不变,确保初始资源被正确打包:

# 单文件打包
pyinstaller --name SmartTank --onefile --windowed --icon=icon.ico --add-data "database;database" --add-data "images;images" --add-data "font;font" main.py

# 非单文件打包
pyinstaller --name SmartTank --windowed --icon=icon.ico --add-data "database;database" --add-data "images;images" --add-data "font;font" main.py

步骤4:调整Inno Setup配置

无需给Program Files目录添加写入权限,数据已存储在用户专属目录。典型脚本片段:

[Setup]
AppName=SmartTank
AppVersion=1.0
DefaultDirName={pf}\SmartTank
DefaultGroupName=SmartTank
OutputDir=output
OutputBaseFilename=SmartTankInstaller
SetupIconFile=icon.ico

[Files]
Source: "dist\SmartTank\*"; DestDir: "{app}"; Flags: recursesubdirs createallsubdirs

[Icons]
Name: "{group}\SmartTank"; Filename: "{app}\SmartTank.exe"
Name: "{commondesktop}\SmartTank"; Filename: "{app}\SmartTank.exe"; Tasks: desktopicon

关键说明

  1. 原方法失效原因
    • 单文件打包时,_MEIPASS是临时目录,程序退出后自动删除,数据无法持久化。
    • 安装到Program Files后,普通用户无写入权限,无法修改目录内文件。
  2. 跨平台兼容性
    • get_app_data_dir自动适配各系统标准应用数据目录,符合系统规范。
  3. 初始数据复制逻辑
    • 首次运行时自动将打包的初始模板复制到用户目录,后续读写操作副本,避免权限与丢失问题。

内容的提问来源于stack exchange,提问作者SKevinAR18

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 13:02:02