背景
最近我编写了一个Python脚本,该脚本需要依赖两个同级目录下的文件才能正常运行。然而,当我将脚本打包成EXE程序后,必须将这两个文件放在EXE文件的同级目录下才能正常执行。为了简化部署,我希望能将这两个文件一起打包到EXE文件中,这时候该怎么办呢?
解决方案
在这里,我选择使用PyInstaller
将Python脚本及其依赖的文件打包成一个独立的EXE文件。PyInstaller
不仅可以打包脚本,还可以打包所需的资源文件和依赖库。
1、 安装 PyInstaller:
可以通过以下命令进行安装:
pip install pyinstaller
2、项目结构:
我需要将python入口文件main.py
和private_key.pem
、public_key.pem
打包成一个EXE文件,项目结构如下所示:
xiaodou-test/ │ ├── main.py ├── public_key.pem ├── private_key.pem
3、修改代码以适应打包后的结构
因为我原来的代码中的文件路径是相对路径,从程序所在目录读取文件,现在修改了打包方式之后,文件路径会有所变化,这时候需要修改代码以适应新的路径。可以使用sys._MEIPASS
来获取临时目录路径。(以下参考代码在开发的时候也能从py文件所在路径下读到文件)
获取路径的代码如下:
import os import sys def resource_path(relative_path): """ 获取资源的绝对路径,适用于开发环境和PyInstaller打包后的环境。 """ try: # PyInstaller创建临时文件夹,并将路径存储在_MEIPASS中 base_path = sys._MEIPASS except Exception: base_path = os.path.abspath(".") return os.path.join(base_path, relative_path) def create_temp_file(filename, content): """ 在临时目录中创建一个文件,并写入指定内容。 参数: filename (str): 要创建的文件名。 content (str): 要写入文件的内容。 返回: str: 创建的文件的绝对路径。 """ try: # PyInstaller创建临时文件夹,并将路径存储在_MEIPASS中 temp_dir = sys._MEIPASS except Exception: temp_dir = os.path.abspath(".") file_path = os.path.join(temp_dir, filename) with open(file_path, 'w') as file: file.write(content) return file_path
因为要做文件的输出,我这里就添加了一个临时目录创建的函数,不涉及的小伙伴,可以不用管这段代码。
main.py
中读取文件的代码:
from resource_utils import resource_path, create_temp_file def main(): private_key_path = resource_path('private_key.pem') public_key_path = resource_path('public_key.pem') print(f"Private key path: {private_key_path}") print(f"Public key path: {public_key_path}") # 读取文件内容 with open(private_key_path, 'r') as private_key_file: private_key = private_key_file.read() with open(public_key_path, 'r') as public_key_file: public_key = public_key_file.read() print("Private Key:", private_key) print("Public Key:", public_key) # 在临时目录中创建一个新的文件并写入内容 new_file_path = create_temp_file('license.txt', 'This is xiaodou license.') print(f"New file created at: {new_file_path}") if __name__ == '__main__': main()
4、使用PyInstaller打包
使用PyInstaller
的--add-data
选项来将外部文件打包进EXE文件中。步骤如下:
- 打开终端或命令提示符,导航到项目目录。
- 执行以下命令打包脚本:
pyinstaller --onefile --add-data "private_key.pem:." --add-data "public_key.pem:." main.py
--onefile
选项表示将所有内容打包成一个独立的EXE文件。--add-data
选项用于指定要打包的外部文件。格式为"source_path;destination_path"
,其中source_path
是文件的路径,destination_path
是文件在EXE中的路径。
其他可以使用的参数:
--noconsole
选项,它会告诉PyInstaller
在Windows上创建一个窗体应用程序而不是控制台应用程序。这样就不会显示命令行窗口。--icon
选项指定图标文件,这个图标将用于生成的可执行文件的显示图标和窗口图标。