¿Cómo escribir datos binarios en stdout en Python 3?

103

En python 2.x podría hacer esto:

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

Ahora, sin embargo, obtengo un TypeError: can't write bytes to text stream. ¿Hay alguna codificación secreta que deba usar?

Ivan Baldin
fuente
4
Sería mucho mejor encontrar una respuesta que funcione con Python 2.6+ y 3.x
sorin
2
os.writefuncionará tanto en Py2 como en Py3.
David Wolever

Respuestas:

169

Una mejor manera:

import sys
sys.stdout.buffer.write(b"some binary data")
Benjamin Peterson
fuente
4
Usar sys.stdout.buffertambién le permite hacer cosas como usar shutil.copyfileobjincluso cuando el objeto del archivo de origen proporciona bytes, y no cadenas. +1
csl
1
Los programas que usan esto no se pueden probar en IDLE 3:AttributeError: 'PseudoOutputFile' object has no attribute 'buffer'
Damian Yerrick
4
@DamianYerrick en IDLE (al menos en Windows) pythonw.exeejecuta IDLE, lo que significa que no hay stdout. Se emula con tkinter. Físicamente no puede manejar bytes. En este caso, .decode('UTF-8', errors='replace')su cadena, o ejecute python3 -I <filename>para obtener un REPL en lugar de usar IDLE.
Artyer
Desordena el orden de escritura al escribir stderrsi se usa junto con print(file=sys.stderr).
Kotauskas
15
import os
os.write(1, a.tostring())

o, os.write(sys.stdout.fileno(), …)si eso es más legible que 1para usted.

Alex Martelli
fuente
Gracias, funcionó. Se siente un poco hack-ish, pero supongo que no es algo tan común.
Ivan Baldin
6
El problema os.writees que tendrás que verificar el valor de retorno, ya que no garantiza que todo se escribirá.
mic_e
10

Una forma idiomática de hacerlo, que solo está disponible para Python 3, es:

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

La parte buena es que utiliza la interfaz de objeto de archivo normal, a la que todos están acostumbrados en Python.

Observe que estoy configurando closefd=Falsepara evitar el cierre sys.stdoutal salir del withbloque. De lo contrario, su programa ya no podrá imprimir en stdout. Sin embargo, para otros tipos de descriptores de archivo, es posible que desee omitir esa parte.

Yajo
fuente
¿Por qué te ruborizas? ¿No es mejor dejar que Python decida cuándo vaciar stdout?
Martin
0

En caso de que desee especificar una codificación en python3, aún puede usar el comando bytes como se muestra a continuación:

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

donde 1 es el número habitual correspondiente para stdout -> sys.stdout.fileno ()

De lo contrario, si no le importa la codificación, simplemente use:

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

Si desea utilizar os.write sin la codificación, intente utilizar lo siguiente:

import os
os.write(1,b"Your string to Stdout\n")
Marco smdm
fuente
1
Los programas que usan os.write(sys.stdout.fileno(), some_bytes)no funcionarán en IDLE. io.UnsupportedOperation: fileno
Damian Yerrick
@DamianYerrick: Tienes razón ... el IDLE no debería usarse de todos modos para probar algo así. En breve: intente abrir el IDLE (tenía el shell python3.5.1) y simplemente importe sys y sys.stdout.fileno () le arrojará un error io, porque en IDLE esta operación no es compatible :-) Siempre es importante para recordar en qué entorno estás trabajando e intentar conseguir lo que sea posible;) Espero que esto aclare tu consulta :-) Que tengas un buen fin de semana.
Marco smdm
Solo menciona una forma de escribir datos binarios reales en stdoutla última.
Kotauskas