使用 Python 3 将 LF 打印到 Windows 标准输出



如何在Windows上将n打印到标准输出?这段代码适用于 Python 2,但不适用于 Python 3:

# set sys.stdout to binary mode on Windows
import sys, os, msvcrt
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
# the length of testfile created with
#     python test_py3k_lf_print.py > testfile
# below should be exactly 4 symbols (23 0A 23 0A)
print("#n#")

Python 3 已经在二进制模式下配置了标准 I/O,但它有自己的 I/O 实现来执行换行转换。您可以手动调用 sys.stdout.buffer.write 以使用二进制模式BufferedWriter,而不是使用 print ,这需要文本模式文件。如果需要使用 print ,则需要不使用通用换行符的新文本 I/O 包装器。例如:

stdout = open(sys.__stdout__.fileno(), 
              mode=sys.__stdout__.mode, 
              buffering=1, 
              encoding=sys.__stdout__.encoding, 
              errors=sys.__stdout__.errors, 
              newline='n', 
              closefd=False)

由于closefd为 false,因此关闭此文件不会关闭原始sys.stdout文件描述符。您可以通过 print("#n#", file=stdout) 显式使用此文件,也可以替换sys.stdout = stdout 。原件可作为sys.__stdout__提供。

背景

Python

3 的 io 模块旨在为所有类文件对象提供跨平台和跨实现(CPython、PyPy、IronPython、Jython)规范,包括抽象基类RawIOBaseBufferedIOBaseTextIOBase。它在_pyio模块中包含一个引用纯Python实现。原始io.FileIO实现的共同点是一组低级POSIX系统调用,如readwrite,这消除了CRT标准不一致的问题。在Windows上,POSIX层只是CRT的低I/O层,但至少仅限于单个平台的怪癖。

Windows的一个怪癖是在其POSIX I/O层中具有非标准文本和二进制模式。Python 通过始终使用二进制模式并在 stdio 文件描述符 1 上调用 setmode 来解决此问题。

Python 可以通过实现 WinFileIO 注册的 RawIOBase 子类来避免使用 Windows CRT 进行 I/O。问题 12939 中有一个建议的补丁。另一个例子是win_unicode_console模块,它实现了WindowsConsoleRawReaderWindowsConsoleRawWriter类。


1. 这给嵌入 Python 并期望 stdio 使用默认文本模式的程序带来了问题。例如,在二进制模式下打印宽字符字符串不再像在 ANSI 文本模式下那样转换为char,并且肯定不会像在 UTF-16 文本模式下那样使用 WriteConsoleW 进行打印。例如:

Python 2.7.10 (default, May 23 2015, 09:44:00) 
[MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys, os, msvcrt, ctypes 
>>> ctypes.cdll.msvcr90.wprintf(b'wx00ix00dx00ex00nx00') 
wide
5
>>> msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) 
16384
>>> ctypes.cdll.msvcr90.wprintf(b'wx00ix00dx00ex00nx00')
w i d e
 5

最新更新