繁体   English   中英

将标准输出重定向到文件时,Windows 上的 Python“处理无效”

[英]Python on Windows "Handle Invalid" when redirecting stdout writing to file

我正在尝试修复的脚本使用以下范例将标准输出重定向到文件。

import os
stdio_file = 'temp.out'
flag = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
stdio_fp = os.open(stdio_file, flag)
os.dup2(stdio_fp, 1)
print("hello")

在 Python 2 上,这有效。 在 Python 3 上,你得到一个 OSError

Traceback (most recent call last):
  File "test.py", line 6, in <module>
    print("hello")
OSError: [WinError 6] The handle is invalid
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>
OSError: [WinError 6] The handle is invalid

我认为有更可取的方法通过文件路由标准输出,但我想知道为什么这种方法在 Python 3 中停止工作,是否有一种简单的方法来修复它?

诸如os.dup2(stdio_fp, 1)将在 Python 3.5 及更早版本中工作,或者在 3.6+ 中使用定义的环境变量PYTHONLEGACYWINDOWSSTDIO

问题是print写入仅用于控制台 I/O 的sys.stdout对象。 具体来说,在 3.6+ 中,当 stdout 最初是控制台文件1时,Python 3 的标准输出文件(即sys.stdout.buffer.raw )的原始层是一个io._WindowsConsoleIO实例。 该对象缓存 stdout 文件描述符2的初始句柄值。 随后, dup2关闭此句柄,同时将文件描述符与“temp.out”的重复句柄重新关联。 此时缓存的句柄不再有效。 (实际上,它不应该缓存句柄,因为与控制台 I/O 的成本相比,调用_get_osfhandle的成本相对较低。)但是,即使它具有“temp.out”的有效句柄, sys.stdout.write无论如何都会失败,因为_WindowsConsoleIO使用仅限控制台的函数WriteConsoleW而不是通用的WriteFile

您需要重新分配sys.stdout而不是使用dup2等低级操作绕过 Python 的 I/O 堆栈。 我知道从 Unix 开发人员的角度来看这并不理想。 我希望我们可以重新实现 Windows 控制台支持 Unicode 的方式,而不引入这个仅限控制台的_WindowsConsoleIO类,这会破坏人们数十年来依赖的低级模式。


1. _WindowsConsoleIO被添加到在Windows 控制台中支持全范围的Unicode(至少以及控制台可以支持它)。 为此,它使用控制台的 UTF-16 宽字符 API(例如ReadConsoleWWriteConsoleW )。 以前,CPython 的控制台支持仅限于使用 Windows 代码页编码的文本,使用通用的基于字节的 I/O(例如ReadFileWriteFile )。

2. Windows 使用句柄来引用内核对象,例如 File 对象。 该系统在行为上与 POSIX 文件描述符 (FD) 不兼容。 因此,C 运行时 (CRT) 具有“低 I/O”兼容性层,它将 POSIX 样式的 FD 与 Windows 文件句柄相关联,并且它还实现了 POSIX I/O 功能,例如openwrite CRT的_open_osfhandle功能的原生文件句柄与FD和同事_get_osfhandle回报与FD关联的句柄。 有时CPython使用CRT低I/O层,有时直接使用Windows API。 如果你问我,这真的有点乱。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM