You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

PyInstaller编译Python程序中print()抛出OSError: [Errno 22]异常排查

关于PyInstaller打包exe中print()间歇性抛出OSError: Errno22的成因分析与解决

从你的问题描述和错误日志来看,这个间歇性出现的错误完全是Windows控制台输出句柄的不稳定导致的,结合你使用的PyInstaller 3.5版本,具体成因可以拆解为以下几点:

核心原因

  1. PyInstaller 3.5的已知控制台I/O bug
    PyInstaller 3.5是2019年的旧版本,在Windows下打包控制台程序时,对标准输出(stdout)的句柄管理存在缺陷。当你的程序持续运行(每秒输出3次日志),系统资源调度、控制台窗口状态变化(比如最小化、快速切换窗口)或者后台运行时的会话波动,都可能导致控制台输出句柄临时失效。此时print()调用底层Windows API时会传入无效参数,直接抛出Errno 22错误。

  2. 控制台缓冲区的异常状态
    长时间持续输出日志会让控制台缓冲区处于高负载状态,偶尔会出现系统未及时清理缓冲区、缓冲区溢出的情况,触发输出调用失败。而日志写入文件不受影响,是因为文件I/O和控制台I/O用的是完全独立的句柄和处理逻辑——文件路径是稳定的,不会受控制台状态干扰。

  3. 后台运行的控制台会话问题
    如果你的exe是通过脚本、任务计划或其他后台方式启动(而非直接双击打开控制台窗口),Windows可能会在某些场景下临时断开控制台会话的连接,导致print()找不到有效的输出目标,从而抛出“无效参数”的错误。

快速验证方法

你可以通过以下操作确认这个推测:

  • 把PyInstaller升级到4.0以上的稳定版本,重新打包程序——3.5的很多控制台I/O问题在后续版本中已经被修复。
  • 尝试用program.exe > output.log命令运行程序,把标准输出重定向到文件,如果不再出现错误,就坐实了是控制台输出的问题。
  • 直接用Python解释器运行program.py,观察几小时,如果不会报错,进一步确认是PyInstaller打包后的专属问题。

可行的解决方案

  1. 升级PyInstaller(最直接有效)
    执行pip install --upgrade pyinstaller,把版本更新到最新稳定版,重新打包。后续版本针对Windows控制台输出做了大量优化,包括修复句柄泄漏、无效句柄的问题,大概率能直接解决你的异常。

  2. 在打包环境下禁用控制台print(推荐)
    既然你已经有成熟的日志写入逻辑,完全可以在打包后的exe中跳过控制台输出,只保留文件日志。利用PyInstaller打包后会添加的sys._MEIPASS属性来判断运行环境:

import sys
from traceback import format_exc

def log_text(self, text, log_to_disk=True):
    log_text = time_now() + str(text)
    # 仅在本地开发环境(非打包exe)下打印到控制台
    if not hasattr(sys, '_MEIPASS'):
        try:
            print(log_text)
        except:
            self.log_to_txt(format_exc())
            self.log_to_txt(f"Print statement raised error while printing '{log_text}'")
    if log_to_disk:
        self.log_to_txt(log_text)
  1. 重定向stdout到日志文件
    在程序启动时把标准输出和错误输出都重定向到日志文件,这样所有print()都会自动写入文件,彻底绕开控制台I/O的问题:
import sys
import os

# 仅在打包后的exe环境中执行重定向
if hasattr(sys, '_MEIPASS'):
    log_path = os.path.join(os.path.dirname(sys.executable), 'console_output.log')
    # 打开日志文件,追加模式
    console_log = open(log_path, 'a', encoding='utf-8')
    # 重定向标准输出和错误输出
    sys.stdout = console_log
    sys.stderr = console_log

内容的提问来源于stack exchange,提问作者Darius

火山引擎 最新活动