Как записать двоичные данные в стандартный вывод в python 3?

В python 2.x я мог бы сделать это:

import sys, array
a = array.array('B', range(100))
a.tofile(sys.stdout)

Однако теперь я получаю TypeError: can't write bytes to text stream. Есть ли какая-то секретная кодировка, которую я должен использовать?


person Ivan Baldin    schedule 25.05.2009    source источник
comment
Было бы намного лучше найти ответ, который будет работать с Python 2.6+ и 3.x.   -  person sorin    schedule 14.06.2010
comment
os.write будет работать как на Py2, так и на Py3.   -  person David Wolever    schedule 26.04.2014


Ответы (4)


Лучший способ:

import sys
sys.stdout.buffer.write(b"some binary data")
person Benjamin Peterson    schedule 26.05.2009
comment
Использование sys.stdout.buffer также позволяет вам делать такие вещи, как использование shutil.copyfileobj, даже когда объект исходного файла дает байты, а не строки. +1 - person csl; 19.06.2015
comment
Программы, использующие это, нельзя тестировать в IDLE 3: AttributeError: 'PseudoOutputFile' object has no attribute 'buffer' - person Damian Yerrick; 18.05.2017
comment
@DamianYerrick в IDLE (по крайней мере, в Windows) pythonw.exe запускает IDLE, что означает отсутствие стандартного вывода. Он эмулируется с помощью tkinter. Он физически не может обрабатывать байты. В этом случае .decode('UTF-8', errors='replace') введите свою строку или запустите python3 -I <filename>, чтобы получить REPL вместо использования IDLE. - person Artyer; 21.05.2017
comment
Путает порядок записи при записи в stderr при использовании вместе с print(file=sys.stderr). - person Kotauskas; 19.07.2019
comment
@Kotauskas, ты звонишь флеш после того, как написал? - person Myles Hollowed; 07.04.2021

import os
os.write(1, a.tostring())

или os.write(sys.stdout.fileno(), …), если это более читабельно, чем 1 для вас.

person Alex Martelli    schedule 25.05.2009
comment
Спасибо, это сработало. Чувствуется немного хакерский, но я думаю, что это не так уж часто. - person Ivan Baldin; 26.05.2009
comment
Проблема с os.write заключается в том, что вам придется проверять возвращаемое значение, так как это не гарантирует, что все будет записано. - person mic_e; 01.09.2015

Идиоматический способ сделать это, доступный только для Python 3, таков:

with os.fdopen(sys.stdout.fileno(), "wb", closefd=False) as stdout:
    stdout.write(b"my bytes object")
    stdout.flush()

Хорошая часть заключается в том, что он использует обычный интерфейс файловых объектов, к которому все привыкли в Python.

Обратите внимание, что я устанавливаю closefd=False, чтобы избежать закрытия sys.stdout при выходе из блока with. В противном случае ваша программа больше не сможет печатать на стандартный вывод. Однако для других видов файловых дескрипторов вы можете пропустить эту часть.

person Yajo    schedule 07.01.2019
comment
Почему вы смываетесь? Не лучше ли позволить Python решать, когда очищать стандартный вывод? - person Martin; 20.10.2019
comment
Нельзя ли существующий канал, такой как sys.stdout, как-то перевести в бинарный режим (а потом обратно), не открывая поверх него новый? - person Mikhail T.; 19.02.2021
comment
Я так не думаю. Кстати, я очищаю, потому что в противном случае fd будет закрыт. Возможно, Python все равно сбросил бы... вы можете попробовать и сообщить. - person Yajo; 17.03.2021

Если вы хотите указать кодировку в python3, вы все равно можете использовать команду bytes, как показано ниже:

import os
os.write(1,bytes('Your string to Stdout','UTF-8'))

где 1 — соответствующий обычный номер для stdout --> sys.stdout.fileno()

В противном случае, если вам не нужна кодировка, просто используйте:

import sys
sys.stdout.write("Your string to Stdout\n")

Если вы хотите использовать os.write без кодировки, попробуйте использовать следующее:

import os
os.write(1,b"Your string to Stdout\n")
person Marco smdm    schedule 13.04.2015
comment
Программы, использующие os.write(sys.stdout.fileno(), some_bytes), не будут работать в IDLE. io.UnsupportedOperation: fileno - person Damian Yerrick; 18.05.2017
comment
@DamianYerrick: Вы правы ... IDLE в любом случае не следует использовать для тестирования чего-то подобного. Вкратце: попробуйте открыть IDLE (у меня была оболочка python3.5.1) и просто импортировать sys и sys.stdout.fileno(), это выдаст вам ошибку io, потому что в IDLE это не поддерживается операция :-) Это всегда важно чтобы помнить, в какой среде вы работаете, и попытаться получить то, что возможно ;) Надеюсь, это прояснит ваш вопрос :-) Хороших выходных. - person Marco smdm; 19.05.2017
comment
Вы упоминаете только один способ записи фактических двоичных данных в stdout, последний. - person Kotauskas; 19.07.2019