【问题标题】:Print LF with Python 3 to Windows stdout使用 Python 3 将 LF 打印到 Windows 标准输出
【发布时间】:2016-04-29 21:27:58
【问题描述】:

如何在 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#")

【问题讨论】:

    标签: windows python-3.x stdout


    【解决方案1】:

    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 为假,关闭此文件不会关闭原始sys.stdout 文件描述符。您可以通过print("#\n#", file=stdout) 显式使用此文件,或替换sys.stdout = stdout。原文地址为sys.__stdout__

    背景

    Python 3 的 io 模块旨在为抽象基类 RawIOBaseBufferedIOBase、和TextIOBase。它在 _pyio 模块中包含一个参考纯 Python 实现。原始io.FileIO 实现的共同点是一组低级POSIX 系统调用,例如readwrite,它消除了CRT stdio 不一致的问题。在 Windows 上,POSIX 层只是 CRT 的低 I/O 层,但至少仅限于单一平台的怪癖。

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

    Python 可以通过实现 WinFileIO 的注册子类 RawIOBase 来避免使用 Windows CRT 进行 I/O。在issue 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'w\x00i\x00d\x00e\x00\n\x00') 
    wide
    5
    >>> msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) 
    16384
    >>> ctypes.cdll.msvcr90.wprintf(b'w\x00i\x00d\x00e\x00\n\x00')
    w i d e
     5
    

    【讨论】:

    • grief for programs that embed Python and expect stdio to use the default text mode - 谁在期待它,为什么?对我来说,这在 Windows 上是一个令人头疼的问题,因为它会破坏重定向的二进制流。
    • 人们在控制台打印wchar_t字符串期望文本模式,因为CRT至少将它们转换为char(对于ASCII来说已经足够了),而在二进制模式下它只写入原始宽字符,其中p r i n t s l i k e t h i s.
    • 我添加了一个 ctypes 示例,演示了在二进制模式下调用 CRT 的 wprintf 函数时遇到的问题。
    • 天啊。一整罐蠕虫。 =)
    • 换行符的自动转换可能是一个难以追踪的野兽。当在 atom 的 process-pallette 内部查看输出时,我的 prints 似乎加倍换行符时,我确切地知道发生了什么,但我不知道如何禁用通用换行符转换——当然,我直接调用sys.stdout.write() 的尝试也失败了——离问题更近了一步,但仍然走错了路。您重新定义 sys.stdout 的代码运行良好,谢谢。
    猜你喜欢
    • 2013-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-08
    • 1970-01-01
    • 2012-04-14
    相关资源
    最近更新 更多