Come scrivere dati binari su stdout in Python 3?


103

In python 2.x potrei fare questo:

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

Ora, tuttavia, ottengo un TypeError: can't write bytes to text stream. C'è qualche codifica segreta che dovrei usare?


4
Sarebbe molto meglio trovare una risposta che funzioni con Python 2.6+ e 3.x
sorin

2
os.writefunzionerà sia su Py2 che su Py3.
David Wolever

Risposte:


169

Un modo migliore:

import sys
sys.stdout.buffer.write(b"some binary data")

4
L'uso sys.stdout.bufferti consente anche di fare cose come usare shutil.copyfileobjanche quando l'oggetto file di origine fornisce byte e non stringhe. +1
csl

1
I programmi che lo utilizzano non possono essere testati in IDLE 3:AttributeError: 'PseudoOutputFile' object has no attribute 'buffer'
Damian Yerrick

4
@DamianYerrick in IDLE (almeno in Windows) pythonw.exeesegue IDLE, il che significa che non c'è stdout. È emulato con tkinter. Fisicamente non può gestire i byte. In questo caso, la .decode('UTF-8', errors='replace')tua stringa o esegui python3 -I <filename>per ottenere un REPL invece di usare IDLE.
Artyer

Incasina l'ordine delle scritture durante la scrittura stderrse si utilizza insieme a print(file=sys.stderr).
Kotauskas

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

oppure, os.write(sys.stdout.fileno(), …)se è più leggibile di 1te.


Grazie, ha funzionato. Sembra un po 'hacker, ma immagino che non sia una cosa comune da fare.
Ivan Baldin

6
Il problema os.writeè che dovrai controllare il valore restituito, poiché non garantisce che tutto verrà scritto.
mic_e

10

Un modo idiomatico per farlo, disponibile solo per Python 3, è:

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

La parte buona è che utilizza la normale interfaccia oggetto file, a cui tutti sono abituati in Python.

Notare che sto impostando closefd=Falseper evitare la chiusura sys.stdoutquando esco dal withblocco. Altrimenti, il tuo programma non sarebbe più in grado di stampare su stdout. Tuttavia, per altri tipi di descrittori di file, potresti voler saltare quella parte.


Perché arrossisci? Non è meglio lasciare che Python decida quando scaricare lo stdout?
Martin

0

Nel caso in cui desideri specificare una codifica in python3, puoi comunque utilizzare il comando bytes come di seguito:

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

dove 1 è il numero abituale corrispondente per stdout -> sys.stdout.fileno ()

Altrimenti se non ti interessa la codifica usa solo:

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

Se vuoi usare os.write senza la codifica, prova a usare quanto segue:

import os
os.write(1,b"Your string to Stdout\n")

1
I programmi che utilizzano os.write(sys.stdout.fileno(), some_bytes)non funzioneranno in IDLE. io.UnsupportedOperation: fileno
Damian Yerrick

@DamianYerrick: hai ragione ... l'IDLE non dovrebbe essere usato comunque per testare qualcosa del genere. In breve: prova ad aprire IDLE (avevo la shell python3.5.1) e importa semplicemente sys e sys.stdout.fileno () ti verrà generato un errore io, perché in IDLE questa operazione non è supportata :-) È sempre importante per ricordare in quale ambiente stai lavorando e cercare di ottenere ciò che è possibile;) Spero che questo chiarisca la tua domanda :-) Buon fine settimana.
Marco smdm

Si menziona solo un modo per scrivere dati binari effettivi stdout, l'ultimo.
Kotauskas
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.