Como escrever dados binários para stdout em python 3?

103

Em python 2.x, eu poderia fazer isso:

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

Agora, porém, recebo um TypeError: can't write bytes to text stream. Existe alguma codificação secreta que devo usar?

Ivan Baldin
fonte
4
Seria muito melhor encontrar uma resposta que funcione com Python 2.6+ e 3.x
sorin
2
os.writefuncionará em Py2 e Py3.
David Wolever

Respostas:

169

Uma maneira melhor:

import sys
sys.stdout.buffer.write(b"some binary data")
Benjamin Peterson
fonte
4
Usar sys.stdout.buffertambém permite fazer coisas como usar, shutil.copyfileobjmesmo quando o objeto do arquivo de origem fornece bytes, e não strings. +1
csl
1
Os programas que usam isso não podem ser testados no IDLE 3:AttributeError: 'PseudoOutputFile' object has no attribute 'buffer'
Damian Yerrick
4
@DamianYerrick no IDLE (pelo menos no Windows) pythonw.exeexecuta o IDLE, o que significa que não há stdout. Ele é emulado com tkinter. Ele fisicamente não pode lidar com bytes. Neste caso, .decode('UTF-8', errors='replace')sua string ou execute python3 -I <filename>para obter um REPL em vez de usar o IDLE.
Artyer de
Confunde a ordem das gravações ao escrever para stderrse usar junto com print(file=sys.stderr).
Kotauskas
15
import os
os.write(1, a.tostring())

ou, os.write(sys.stdout.fileno(), …)se for mais legível do que 1para você.

Alex Martelli
fonte
Obrigado, funcionou. Parece um pouco hack, mas acho que não é uma coisa comum de se fazer.
Ivan Baldin
6
O problema os.writeé que você terá que verificar o valor de retorno, pois isso não garante que tudo será escrito.
mic_e 01 de
10

Uma maneira idiomática de fazer isso, que está disponível apenas para Python 3, é:

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

A parte boa é que ele usa a interface de objeto de arquivo normal, com a qual todos estão acostumados em Python.

Observe que estou definindo closefd=Falsepara evitar o fechamento sys.stdoutao sair do withbloco. Caso contrário, seu programa não seria mais capaz de imprimir em stdout. No entanto, para outros tipos de descritores de arquivo, você pode querer pular essa parte.

Yajo
fonte
Por que você dá descarga? Não é melhor deixar o Python decidir quando liberar o stdout?
Martin de
0

Caso queira especificar uma codificação em python3, você ainda pode usar o comando bytes como abaixo:

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

onde 1 é o número usual correspondente para stdout -> sys.stdout.fileno ()

Caso contrário, se você não se importar com a codificação, use:

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

Se você deseja usar o os.write sem a codificação, tente usar o seguinte:

import os
os.write(1,b"Your string to Stdout\n")
Marco smdm
fonte
1
Programas que usam os.write(sys.stdout.fileno(), some_bytes)não funcionam no IDLE. io.UnsupportedOperation: fileno
Damian Yerrick
@DamianYerrick: Você está certo ... o IDLE não deve ser usado para testar algo assim. Resumindo: tente abrir o IDLE (eu tinha o shell python3.5.1) e simplesmente importe sys e sys.stdout.fileno () isso vai gerar o erro io, porque em IDLE essa operação não é suportada :-) É sempre importante para lembrar em qual ambiente você está trabalhando e tentar conseguir o que é possível;) Espero que isso esclareça sua dúvida :-) Tenha um bom final de semana.
Marco smdm
Você mencionou apenas uma maneira de gravar dados binários reais stdout, a última.
Kotauskas