Pyinstaller无法将信息插入到sqlite数据库文件--onefile中

时间:2015-11-21 02:02:24

标签: python database sqlite pyinstaller

我正在尝试使用Pyinstaller构建单文件EXE文件,该文件包含Sqlite数据库文件,它无法与--onefile一起使用,但在正常情况下意味着(许多文件)它正在100%工作。

我正在做的是.py脚本:

import os, sys
def resource_path(relative_path):
    try:
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)

我用它来包含Sqlite文件,它正在100%工作 在.spec文件中我输入:

a.datas.append(('sqlite.db', 'sqlite.db', 'DATA'))

当我构建它的文件很多时它100%工作,我可以从我的应用程序插入信息,但作为--onefile我不能

我可以用Sqlite数据库做这个吗?如果我不能有任何数据库帮助我吗?

3 个答案:

答案 0 :(得分:4)

如果您使用 - onefile 选项(即将所有内容捆绑到一个可执行文件中),当您运行 your_app_name.exe 时,Pyinstaller会将您的数据解压缩为临时文件夹和路径设置为sys._MEIPASS。

def path_to_temp(relative_path):
    try:
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")

    return os.path.join(base_path, relative_path)

因此,当您启动应用程序时,您在规范文件中指定的数据文件也将被提取到此临时位置。

a.datas.append(('sqlite.db', 'sqlite.db', 'DATA'))

您可以访问临时位置来检查提取的文件。只需将其添加到上面的代码

即可获得其路径
print  base_path

现在,您还将看到您的数据库文件。现在对其进行一些更改。然后退出您的应用并再次启动它。获取新的临时位置,并检查您所做的更改是否得到反映。答案是。 因为它没有重新打包提取的文件。

因此,数据文件可以是图像或声音文件等文件,甚至是程序不会修改的数据库文件。

您无需在捆绑的exe中包含数据库文件。而是通过应用程序的名称在Appdata内的运行时创建一个文件夹,并将数据库文件存储在那里。

使用sqlite3的应用程序示例。

dir_path = os.path.join(os.environ['APPDATA'], 'YOUR_APP_NAME')
if not os.path.exists(dir_path):
     os.makedirs(dir_path)
file_path = os.path.join(dir_path, 'your_database_file.sqlite')
sqlite3.connect(file_path)

这将根据AppData \ Roaming目录中的应用名称创建一个文件夹,您的数据库文件将存储在那里。

答案 1 :(得分:2)

您将能够访问包中的SQLite文件,但只能以只读方式访问。因此无法添加新信息。您将遇到类似嵌入式数据库的同一问题。

您可以单独打包SQLite文件,也可以克隆文件并从外部读取文件。

答案 2 :(得分:0)

对于所有在 2021 年仍对此感到摸不着头脑的人,您可以执行以下操作:

  • 不要将数据库打包到您的 EXE 中
  • 将 --runtime-hook = hook.py 添加到您的 pyinstaller 命令或 SPEC 文件中。

在您的 EXE 被提取之前,钩子将一直运行。因此,在这里您可以编写所有必要的代码来生成包含所有表和内容的数据库,并将其移动到您想要的文件夹中。 (我试过了,挺快的)

所以当你第一次打开你的 EXE 时,你可以让 hook.py 生成目录和数据库(如果它们不存在)。第一次运行您的 EXE 时,将创建目录和数据库,如果您第二次打开您的 EXE,这将继续抓取您第一次运行时创建的数据库,允许您修改它。此外,其他将运行您的 EXE 的人,他们将拥有自己的个人数据库。

target_dir = "C:\\Users\\YOURUSERNAME\\AppData\\Local\\YOURAPPNAME\\db"
if not os.path.exists(target_dir):
    os.makedirs(target_dir)
    connection = sqlite3.connect(target_dir + "\\YOURDATABASE.db")
    db = connection.cursor()
    create_starting_db(db)

在 create_starting_db(db) 中放置所有 CREATE 和 INSERT 命令的位置。