【问题标题】:Pyinstaller app can't read but can write to filesPyinstaller 应用程序无法读取但可以写入文件
【发布时间】:2021-11-03 14:30:35
【问题描述】:

我做了一个简单的密码存储应用程序,但我只放了可能有问题的代码。当我从 python 运行这段代码时,它会按照我想要的方式运行,但是当我使用 pyinstaller 转换它时,它并不能按照我想要的方式运行。 每次我尝试注册并重新启动程序时,它都希望我一次又一次地注册。 当我在 storage.py 中登录信息并将注册变量设置为 True 然后将文件转换为 exe 时,它​​可以工作,但没有注册屏幕,只有登录屏幕。 此外,当我更改登录信息时,它不适用于新登录信息,我仍然必须使用旧登录信息。 我认为读取文件存在问题,因为写作效果很好。 我尝试了 --onedir 和 --onefile 模式,还使用 ​​--add-data 添加文件,但仍然没有。

密码存储.py 文件:

from tkinter import *
from tkinter import messagebox
from resources.storage import *

root = Tk()
root.title('Password Storage')
root.iconbitmap('resources/password_storage.ico')

frame1 = LabelFrame(root, padx=10, pady=10)
frame1.grid(row=0, column=0, padx=5, pady=5)

def submit_register():
    if username_register != '' and password_register != '':
        registered = True
        with open('resources/storage.py', 'w') as storage:
            storage.write(f'\nregistered = {registered}\nstorage_username = \'{hashing(username_register.get())}'
                          f'\'\nstorage_password = \'{hashing(password_register.get())}\'')
            storage.write('\n\nstorage = {\n')
            for key, value in passwords.items():
                storage.write(f'\t\'{key}\': {value},\n')
            storage.write('}\n')
        if messagebox.showinfo('Info', 'Successfully saved. Application needs to be restarted.') == 'ok':
            root.quit()
    else:
        messagebox.showerror('Error', 'You didn\'t fill all input fields!')


def submit_login():
    if username_login.get() == storage_username and password_login.get() == storage_password:
        for widget in frame1.winfo_children():
            widget.grid_forget()
    else:
        messagebox.showerror('Error', 'Wrong username or password!')


if not registered:
    for widget in frame1.winfo_children():
        widget.grid_forget()
    Label(frame1, text='Register').grid(row=0, columnspan=2)
    Label(frame1, text='New username: ').grid(row=1, column=0)
    username_register = Entry(frame1, borderwidth=3)
    username_register.grid(row=1, column=1)
    Label(frame1, text='New password: ').grid(row=2, column=0)
    password_register = Entry(frame1, borderwidth=3)
    password_register.grid(row=2, column=1)
    Button(frame1, text='Submit', command=submit_register).grid(row=3, columnspan=2)

elif registered:
    for widget in frame1.winfo_children():
        widget.grid_forget()
    Label(frame1, text='Login').grid(row=0, columnspan=2)
    Label(frame1, text='Username: ').grid(row=1, column=0)
    username_login = Entry(frame1, borderwidth=3)
    username_login.grid(row=1, column=1)
    Label(frame1, text='Password: ').grid(row=2, column=0)
    password_login = Entry(frame1, borderwidth=3)
    password_login.grid(row=2, column=1)
    Button(frame1, text='Submit', command=submit_login).grid(row=3, columnspan=2)

storage.py 文件:

registered = False
storage_username = ''
storage_password = ''

storage = {
}

【问题讨论】:

  • 提供minimal reproducible example,导入时不要使用*
  • 您的程序将密码作为 Python 源代码存储在 storage.py 中。当您运行pyinstaller 时,它会将源代码转换为字节码,而该字节码将被包装到.exe 中。您的程序可能对storage.py 的源代码进行的任何后续更改都不会影响.exe 的行为方式:您的代码仍冻结在原始版本中。这就是它的工作原理。如果您想使用pyinstaller,那么将数据存储为 Python 源不是一个好的解决方案。看看pickle 模块,它最像你正在做的,或者configparser
  • 谢谢,我会试试 BoarGules。顺便说一句,Matiiss,* 东西不起作用。
  • 我可以用二进制模式写吗?
  • 好吧,如果你愿意,你可以自己制作二进制文件布局,但是pickle 模块是一个很好的方法,它比你自己编写和调试的优势在于它是易于编写和调试的,并且将保存和加载任何 Python 数据结构,无论每行代码多么复杂。将其设置为方便的标准,并诚实地问自己是否认为自己也可以做到。如果你关心这些事情(虽然我无法想象为什么)pickle 的默认协议二进制。

标签: python tkinter pyinstaller


【解决方案1】:

按照 BoadGules 在 cmets 中的建议,我使这个程序与 pickle 模块一起工作。非常感谢!

“您的程序将密码作为 Python 源代码存储在 storage.py 中。当您运行 pyinstaller 时,它会将源代码转换为字节码,而该字节码将被包装到 .exe 中。任何后续更改您的程序可能对storage.py 的源产生影响,但对.exe 的行为方式没有影响:您的代码仍冻结在原始版本。这就是它的工作原理。如果您想使用pyinstaller,则存储数据因为 Python 源代码不是一个好的解决方案。看看pickle 模块,它最像你正在做的事情,或者configparser。"

【讨论】:

    猜你喜欢
    • 2022-11-10
    • 2016-01-04
    • 2012-05-03
    • 2018-02-22
    • 1970-01-01
    • 2011-11-16
    • 2017-01-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多