Код, такой как os.dup2(stdio_fp, 1)
, будет работать в Python 3.5 и более ранних версиях или в версии 3.6+ с определенной переменной среды PYTHONLEGACYWINDOWSSTDIO
.
Проблема в том, что print
выполняет запись в объект sys.stdout
, предназначенный только для консольного ввода-вывода.В частности, в версии 3.6+ необработанный слой стандартного выходного файла Python 3 (т.е. sys.stdout.buffer.raw
) является экземпляром io._WindowsConsoleIO
, когда stdout изначально является консольным файлом 1 .Этот объект кэширует начальное значение дескриптора дескриптора файла stdout 2 .Впоследствии dup2
закрывает этот дескриптор, повторно связывая дескриптор файла с дублирующим дескриптором для «temp.out».В этот момент кэшированный дескриптор больше не действителен.(Действительно, он не должен кэшировать дескриптор, так как вызов _get_osfhandle
относительно дешев по сравнению со стоимостью консольного ввода-вывода.) Однако, даже если у него был действительный дескриптор для «temp.out», sys.stdout.write
в любом случае потерпит неудачу, поскольку _WindowsConsoleIO
использует только консольную функцию WriteConsoleW
вместо универсального WriteFile
.
Вам нужно переназначить sys.stdout
вместо обхода стека ввода / вывода Python с помощью низкоуровневых операций, таких каккак dup2
.Я знаю, что это не идеально с точки зрения разработчика Unix.Хотелось бы, чтобы мы снова реализовали способ поддержки Unicode для консоли Windows, не вводя этот класс _WindowsConsoleIO
только для консоли, который нарушает низкоуровневые шаблоны, на которые люди полагались десятилетиями.
1._WindowsConsoleIO
был добавлен для поддержки всего диапазона Unicode в консоли Windows (по крайней мере, так же, как консоль может поддерживать его).Для этого он использует консольный API UTF-16 (например, ReadConsoleW
и WriteConsoleW
).Ранее поддержка консоли CPython была ограничена текстом, который был закодирован с помощью кодовых страниц Windows, с использованием универсального байтового ввода-вывода (например, ReadFile
и WriteFile
).
2.Windows использует дескрипторы для ссылки на объекты ядра, такие как объекты File.Эта система не совместима по поведению с файловыми дескрипторами POSIX (FD).Таким образом, среда выполнения C (CRT) имеет уровень совместимости с низким уровнем ввода-вывода, который связывает FD в стиле POSIX с дескрипторами файлов Windows, а также реализует функции ввода-вывода POSIX, такие как open
и write
.Функция _open_osfhandle
CRT связывает собственный дескриптор файла с FD, а _get_osfhandle
возвращает дескриптор, связанный с FD.Иногда CPython использует низкий уровень ввода-вывода CRT, а иногда напрямую использует Windows API.Это действительно беспорядок, если вы спросите меня.