pyinstaller打包找不到文件的问题解决


Posted in Python onApril 15, 2020

1、将python程序打包成单文件(使用 -F 参数)后,尝试运行外部文件却提示找不到的问题

当你将python程序打包成单文件(使用 -F 参数)后,运行程序,它实际上是先将exe内的资源文件解压到临时文件夹,然后再运行的,所以会导致这种问题

比如,当你在程序里面调用一个外部exe时,但却提示找不到该exe文件。

例子(这里我用win32api去隐式运行外部exe文件):

import win32api
win32api.ShellExecute(0, 'open', 'nginx.exe', '', '', 0)

首先,你需要将这个外部的exe文件添加进pyinstaller的打包里。

有两种方法:

1、直接用参数添加:

--add-data "nginx.exe;."

完整命令:pyinstaller -F main.py --add-data "nginx.exe;."

2、在spec文件添加:

每次执行pyinstaller打包命令后会生成spec文件,打开它
在里面找到data=[] 列表,添加元素,变成了:datas=[('nginx.exe', '.')]
然后用spec打包:pyinstaller main.spec
我解释一下这个点“.”是什么意思:

由于使用单文件打包出来的exe会先解压再运行,所以点“.” 其实表示你打包的这个exe文件运行解压的完整路径

如:C:\...\temp(临时文件夹)\asdqwezxc(你程序运行时自动解压到的目录)

  • 所以这个nginx.exe 被打包后,会解压到 C:\...\temp\asdqwezxc\nginx.exe
  • 如果把点“.”改为test,就会解压到 C:\...\temp\asdqwezxc\test\nginx.exe
  • 以此类推

好,现在nginx.exe已被打包。然后要注意一个问题:

打包出来的exe在运行时,它的工作路径和它解压到的路径,是不一样的!

你可以测试一下:

import os
print(os.getcwd())

可以发现,打印出来的工作路径并不是它运行时解压到的路径!
而是这个打包出来的exe,它本身所存在的路径!

问题来了:

诸如open('xxx.txt')这些操作文件的函数,一般首先都是在工作路径查找你所指定的文件的。

所以,当我们直接这样执行已打包的外部文件时,程序会报找不到文件!所以请使用它的解压路径。

下面提供一个函数,可以很方便的获取到解压路径:

import os, sys
def base_path(path):
  if getattr(sys, 'frozen', None):
    basedir = sys._MEIPASS
  else:
    basedir = os.path.dirname(__file__)
  return os.path.join(basedir, path)

print(base_path(''))
print(base_path('test\gg.exe'))

第一句打印会显示完整的解压路径:

C:\...\temp\asdqwezxc\

第二句打印是这样的:

C:\...\temp\asdqwezxc\test\gg.exe

所以当我们在调用已打包的外部文件时,应该先使用os.chdir()将工作路径改为解压路径:

再进行操作,就不会报文件找不到了

os.chdir(base_path(''))
win32api.ShellExecute(0, 'open', 'nginx.exe', '', '', 0)

不过要注意的是,如果你要写出文件到程序所在的目录(非解压目录),那么你得把工作目录改回来,否则文件会被写出到解压路径(临时文件夹)。

稍微封装一下就好了:

import os, sys

def base_path(path):
  if getattr(sys, 'frozen', None):
    basedir = sys._MEIPASS
  else:
    basedir = os.path.dirname(__file__)
  return os.path.join(basedir, path)

tmd = base_path('') # 这是解压路径
cwd = os.getcwd() # 这是程序的所在路径

# 当需要调用打包的外部文件时
os.chdir(tmd) # 先把工作路径变成解压路径
do() # 执行你要干的事情

# 当需要写出文件到程序所在目录时
os.chdir(cwd) # 把工作路径切换回来
do() # 执行你要干的事情

2、当你使用cython将py文件编译成pyd文件后使用pyinstaller打包,提示找不到模块的问题
直接使用pyinstaller打包py文件是很容易导致源码被反编译的

所以在打包的时候最好将py文件编译成pyd文件,这样可以很大程度上防止反编译。

为什么呢?因为pyd文件的来历是这样的:

py文件 → c文件 → pyd文件
所以直接反编译pyd只能得到上一步cython生成的c文件,而无法得到我们的py源文件。

如何打包pyd成文件请看这篇文章:https://3water.com/article/184725.htm
接下来回到我们的问题。

解决方法很简单,请看:

比如说,我有一个文件main.py,引入了位于同级目录下的test.py模块

# main.py:就像这样直接引入
import test

现在我将test.py 编译成pyd文件,生成了:test.cp37-win_amd64.pyd

这个pyd文件名除了我们原本的文件名test,还会带上编译环境的名称,这个环境后缀名我们可以不用管 ,因为python引入模块还是很智能的(会自动引入.pyd文件,因为它的优先级高于.py文件)。

这么智能,但是为什么我用pyinstaller打包时就提示找不到文件?
其实我们需要在打包时--hidden-import这些模块

1、直接添加

在打包时添加--hidden-import test即可
完整命令:pyinstaller -F --hidden-import test

2、使用spec文件

同样的,运行一次pyinstaller打包命令后会生成spec文件,打开它
找到hiddenimports=[],添加test模块,变成了:hiddenimports=['test']
很简单对吧?
而且除了我们自己写的一些py模块,其它模块在打包时可能也会提示找不到,都可以用这个方法解决。

3、打包成单文件时(使用-F参数),运行时要求管理员权限的参数--uac-admin无效的问题
请看我的这篇文章:pyinstaller打包单文件时?uac-admin选项不起作用怎么办

本质上大概也是因为找不到文件。

4、无控制台打包(使用-w参数),运行时弹框提示Failed to execute script的问题
请看我的这篇文章:pyinstaller打包成无控制台程序时运行出错,与popen冲突的解决方法

这个问题一般是程序内有输入导致的,这个输入可以是input(),也可以是其它的一些stdin操作(如os.popen实际上会造成输入请求)

本质上就是:使用-w参数(无控制台)打包时程序里不要请求输入

当然,实在要用输入,又不想要控制台怎么办?很简单,把控制台隐藏了就行!

下列两个方法,试试看:

import ctypes
def hideConsole():
  """
  Hides the console window in GUI mode. Necessary for frozen application, because
  this application support both, command line processing AND GUI mode and theirfor
  cannot be run via pythonw.exe.
  """

  whnd = ctypes.windll.kernel32.GetConsoleWindow()
  if whnd != 0:
    ctypes.windll.user32.ShowWindow(whnd, 0)
    # if you wanted to close the handles...
    #ctypes.windll.kernel32.CloseHandle(whnd)

def showConsole():
  """Unhides console window"""
  whnd = ctypes.windll.kernel32.GetConsoleWindow()
  if whnd != 0:
    ctypes.windll.user32.ShowWindow(whnd, 1)

暂时就这么多呃,都是本人在打包过程中实际上遇到过的问题和经验。。基本可用

到此这篇关于pyinstaller打包找不到文件的问题解决的文章就介绍到这了,更多相关pyinstaller打包找不到文件内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
python让图片按照exif信息里的创建时间进行排序的方法
Mar 16 Python
在Python的Django框架中更新数据库数据的方法
Jul 17 Python
Django自定义manage命令实例代码
Feb 11 Python
Django 根据数据模型models创建数据表的实例
May 27 Python
Python 使用 attrs 和 cattrs 实现面向对象编程的实践
Jun 12 Python
numpy和pandas中数组的合并、拉直和重塑实例
Jun 28 Python
Python文件操作中进行字符串替换的方法(保存到新文件/当前文件)
Jun 28 Python
python3 打印输出字典中特定的某个key的方法示例
Jul 06 Python
Python实现名片管理系统
Feb 14 Python
Python实现列表中非负数保留,负数转化为指定的数值方式
Jun 04 Python
Keras多线程机制与flask多线程冲突的解决方案
May 28 Python
Python+Selenium实现抖音、快手、B站、小红书、微视、百度好看视频、西瓜视频、微信视频号、搜狐视频、一点号、大风号、趣头条等短视频自动发布
Apr 13 Python
使用Pycharm分段执行代码
Apr 15 #Python
pyinstaller打包成无控制台程序时运行出错(与popen冲突的解决方法)
Apr 15 #Python
pyinstaller打包单文件时--uac-admin选项不起作用怎么办
Apr 15 #Python
在python中利用pycharm自定义代码块教程(三步搞定)
Apr 15 #Python
PyInstaller将Python文件打包为exe后如何反编译(破解源码)以及防止反编译
Apr 15 #Python
Python任务调度模块APScheduler使用
Apr 15 #Python
Python实现代码块儿折叠
Apr 15 #Python
You might like
在php MYSQL中插入当前时间
2008/04/06 PHP
Windows7下PHP开发环境安装配置图文方法
2010/05/20 PHP
Memcached常用命令以及使用说明详解
2013/06/27 PHP
简单介绍PHP的责任链编程模式
2015/08/11 PHP
CI分页类首页、尾页不显示的解决方法
2016/03/28 PHP
windows下的WAMP环境搭建图文教程(推荐)
2017/07/27 PHP
JavaScript.Encode手动解码技巧
2010/07/14 Javascript
Google AJAX 搜索 API实现代码
2010/11/17 Javascript
javascript变量作用域使用中常见错误总结
2013/03/26 Javascript
js 弹出框只弹一次(二次修改之后的)
2013/11/26 Javascript
jQuery之选项卡的简单实现
2014/02/28 Javascript
jQuery on方法传递参数示例
2014/12/09 Javascript
Jquery中$.post和$.ajax的用法小结
2015/04/28 Javascript
浅谈angular懒加载的一些坑
2016/08/20 Javascript
JavaScript 中对象的深拷贝
2016/12/04 Javascript
AngularJS中使用ngModal模态框实例
2017/05/27 Javascript
vue实现验证码按钮倒计时功能
2018/04/10 Javascript
[42:20]Secret vs Liquid 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/17 DOTA
[01:07:19]DOTA2-DPC中国联赛 正赛 CDEC vs XG BO3 第一场 1月19日
2021/03/11 DOTA
python文件比较示例分享
2014/01/10 Python
python中pygame模块用法实例
2014/10/09 Python
Python如何发布程序的详细教程
2018/10/09 Python
利用Python实现微信找房机器人实例教程
2019/03/10 Python
详解Selenium+PhantomJS+python简单实现爬虫的功能
2019/07/14 Python
Django 外键的使用方法详解
2019/07/19 Python
利用python计算时间差(返回天数)
2019/09/07 Python
python装饰器使用实例详解
2019/12/14 Python
pytorch中nn.Conv1d的用法详解
2019/12/31 Python
django自带的权限管理Permission用法说明
2020/05/13 Python
PyCharm+PyQt5+QtDesigner配置详解
2020/08/12 Python
Python将list元素转存为CSV文件的实现
2020/11/16 Python
python编写扎金花小程序的实例代码
2021/02/23 Python
创造美妙香氛体验:Aera扩散器和香水
2018/11/25 全球购物
英文演讲稿
2014/05/15 职场文书
节约用水标语
2014/06/11 职场文书
新农村建设汇报材料
2014/08/15 职场文书