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

104

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

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

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

Иван Балдин
источник
4
Было бы гораздо лучше найти ответ, который будет работать с Python 2.6+ и 3.x
Сорин
2
os.writeбудет работать как на Py2, так и на Py3.
Дэвид Волевер

Ответы:

169

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

import sys
sys.stdout.buffer.write(b"some binary data")
Бенджамин Петерсон
источник
4
Использование sys.stdout.bufferтакже позволяет вам делать такие вещи, как использование, shutil.copyfileobjдаже когда объект исходного файла дает байты, а не строки. +1
csl
1
Программы, использующие это, не могут быть протестированы в IDLE 3:AttributeError: 'PseudoOutputFile' object has no attribute 'buffer'
Дамиан Йеррик,
4
@DamianYerrick в IDLE (по крайней мере, в Windows) pythonw.exeзапускает IDLE, что означает отсутствие стандартного вывода. Эмулируется с помощью tkinter. Он физически не может обрабатывать байты. В этом случае .decode('UTF-8', errors='replace')ваша строка или run python3 -I <filename>для получения REPL вместо использования IDLE.
Artyer
Нарушает порядок записи при записи, stderrесли используется вместе с print(file=sys.stderr).
Kotauskas
15
import os
os.write(1, a.tostring())

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

Алекс Мартелли
источник
Спасибо, сработало. Кажется немного хакерским, но я думаю, что это не так уж и часто.
Иван Балдин
6
Проблема в os.writeтом, что вам придется проверять возвращаемое значение, так как это не гарантирует, что все будет записано.
mic_e 01
11

Идиоматический способ сделать это, доступный только для 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блока. В противном случае ваша программа больше не сможет печатать на стандартный вывод. Однако для других типов файловых дескрипторов вы можете пропустить эту часть.

Yajo
источник
Почему вы промываете? Разве не лучше позволить Python решать, когда сбрасывать стандартный вывод?
Мартин
0

Если вы хотите указать кодировку в 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")
Марко smdm
источник
1
Программы использующие os.write(sys.stdout.fileno(), some_bytes)не будут работать в IDLE. io.UnsupportedOperation: fileno
Дамиан Йеррик
@DamianYerrick: Вы правы ... IDLE в любом случае не следует использовать для тестирования чего-то подобного. Вкратце: попробуйте открыть IDLE (у меня была оболочка python3.5.1) и просто импортируйте sys и sys.stdout.fileno (), это выдаст вам ошибку io, потому что в IDLE это не поддерживается :-) Это всегда важно чтобы запомнить, в какой среде вы работаете, и попытаться получить то, что возможно;) Надеюсь, это прояснит ваш вопрос :-) Хороших выходных.
Marco smdm
Вы упомянули только один способ записи реальных двоичных данных stdout, последний.
Kotauskas