有时候在将一个程序打包成.EXE可执行文件的时候,代码中可能需要引入一些其他的文件,如果将资源文件与程序放在同级目录下,那样也太不优雅了,且发送可执行程序时比较麻烦
pyinstaller
目前普遍的将python代码打包成可执行文件的方法是使用pyinstaller进行打包,它里面有两种模式,一种是将代码打包成一个单独的文件,文件内部包含了所有的支持库;另一种是将代码打包成一个文件夹,文件夹中放着可执行程序和支持库,是可以把需要增加的静态文件放进这个文件夹中的,但是也很容易被找到,且打包成一个文件夹的形式我认为太不优雅了,也不利于发送和传播。
代码内的操作
如果想要把所引入的代码外部文件打包进.EXE本身内部,需要在代码中额外写一个方法:
1 | import os.path |
在这里的relative_path传入的参数就是代码文件和资源文件的相对地址就可以了(因为是有os.path.join,所以文件相对地址开头就不要./了)
我们可以看看这个函数都做了些什么操作:首先它会去判断sys下面有没有一个叫做”frozen”的属性,如果没有找到这个属性,就默认返回false,并根据这个结果返回不同的文件路径。
如果你去sys.py这个文件里查看,你会发现,它里面是并没有定义叫”frozen”这个属性或者方法的,也就是我们在代码中执行的时候,就会执行os.path.join(os.path.abspath(‘.’), relative_path),也就是会将现在代码的地址和传入的相对地址拼接起来,获取到一个新的地址,也就是我们编写代码的时候文件的完整地址,在这个地址去访问对应的文件。
而如果是程序已经被打包完成了,那么在打包的时候pyinstaller会在sys中添加一个”frozen”属性,那么上述代码的if判断就会成功,就会执行os.path.join(sys._MEIPASS, relative_path),打包生成exe后的依赖文件路径就是sys._MEIPASS,如果程序已打包,就会拼接这一个地址,在这个地址中进行查找文件。
–add-data
虽然代码中这么写了,但是我们现在打包的时候还是不知道要指向哪些文件,我们的pyinstaller也不知道要把哪些文件放进程序中呀,这时候我们就需要往打包的data里面进行文件添加了。
我们可以直接使用–add-data <SRC;DEST or SRC:DEST>在进行打包的时候直接将文件添加进去(至于别的参数这里就不进行赘述了),也可以去修改打包时生成的.spec文件,通过记事本打开,可以发现里面有一个data变量,可以直接在那进行更改。
这里的前一个参数是资源文件的路径,后面的参数是资源文件在打包后的可执行文件中的目标路径,也就是程序内部的路径。例如上方图片中的就是直接将同级目录下的文件直接放到文件中的当前目录下,就可以让程序直接读取了。如果是文件夹的话可以(‘resource’,’resource’),也就是将resource这个文件夹传进去,然后放在叫resource这个文件夹的位置。
这样我们打包出来的程序还是只有一个,且能够访问到程序中的资源文件(通常在C:\Windows\Temp_MEIxxx或者C:\Users\用户名\AppData\Local\Temp_MEIxxx中)