Wie schreibe ich Binärdaten in Python 3 auf stdout?

103

In Python 2.x könnte ich das tun:

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

Jetzt bekomme ich jedoch eine TypeError: can't write bytes to text stream. Gibt es eine geheime Codierung, die ich verwenden sollte?

Ivan Baldin
quelle
4
Es wäre viel besser, eine Antwort zu finden, die mit Python 2.6+ und 3.x
funktioniert
2
os.writewird sowohl auf Py2 als auch auf Py3 funktionieren.
David Wolever

Antworten:

169

Ein besserer Weg:

import sys
sys.stdout.buffer.write(b"some binary data")
Benjamin Peterson
quelle
4
Mit sys.stdout.bufferkönnen Sie auch Dinge verwenden, die verwendet werden, shutil.copyfileobjselbst wenn das Quelldateiobjekt Bytes und keine Zeichenfolgen enthält. +1
csl
1
Programme, die dies verwenden, können nicht in IDLE 3 getestet werden:AttributeError: 'PseudoOutputFile' object has no attribute 'buffer'
Damian Yerrick
4
@DamianYerrick in IDLE (zumindest unter Windows) pythonw.exeführt IDLE aus, was bedeutet, dass kein Standard vorhanden ist. Es wird mit tkinter emuliert. Es kann physisch keine Bytes verarbeiten. In diesem Fall .decode('UTF-8', errors='replace')Ihre Zeichenfolge oder ausführen python3 -I <filename>, um eine REPL zu erhalten, anstatt IDLE zu verwenden.
Artyer
Versaut die Reihenfolge der Schreibvorgänge beim Schreiben, stderrwenn sie zusammen mit verwendet werden print(file=sys.stderr).
Kotauskas
15
import os
os.write(1, a.tostring())

oder, os.write(sys.stdout.fileno(), …)wenn das besser lesbar ist als 1für Sie.

Alex Martelli
quelle
Danke, das hat funktioniert. Fühlt sich ein bisschen hackig an, aber ich denke, das ist nicht so üblich.
Ivan Baldin
6
Das Problem dabei os.writeist, dass Sie den Rückgabewert überprüfen müssen, da dies nicht garantiert, dass alles geschrieben wird.
mic_e
10

Eine idiomatische Methode, die nur für Python 3 verfügbar ist, ist:

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

Das Gute daran ist, dass es die normale Dateiobjektschnittstelle verwendet, an die jeder in Python gewöhnt ist.

Beachten Sie, dass ich beim closefd=FalseSchließen sys.stdoutdes withBlocks ein Schließen vermeiden möchte . Andernfalls kann Ihr Programm nicht mehr auf Standard drucken. Bei anderen Arten von Dateideskriptoren können Sie diesen Teil jedoch überspringen.

Yajo
quelle
Warum spülst du? Ist es nicht besser, Python entscheiden zu lassen, wann stdout gelöscht werden soll?
Martin
0

Wenn Sie eine Codierung in Python3 angeben möchten, können Sie den folgenden Byte-Befehl weiterhin verwenden:

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

Dabei ist 1 die entsprechende übliche Zahl für stdout -> sys.stdout.fileno ()

Andernfalls, wenn Sie sich nicht für die Codierung interessieren, verwenden Sie einfach:

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

Wenn Sie os.write ohne Codierung verwenden möchten, versuchen Sie, Folgendes zu verwenden:

import os
os.write(1,b"Your string to Stdout\n")
Marco smdm
quelle
1
Programme, die verwenden os.write(sys.stdout.fileno(), some_bytes), funktionieren in IDLE nicht. io.UnsupportedOperation: fileno
Damian Yerrick
@DamianYerrick: Du hast recht ... der IDLE sollte sowieso nicht verwendet werden, um so etwas zu testen. Kurz: Versuchen Sie, den IDLE zu öffnen (ich hatte die python3.5.1-Shell) und importieren Sie einfach sys und sys.stdout.fileno (). Dies führt zu einem Fehler, da dies in IDLE nicht unterstützt wird :-) Es ist immer wichtig um sich zu erinnern, in welcher Umgebung Sie arbeiten und versuchen, das Mögliche zu bekommen;) Hoffe, dies klärt Ihre Frage :-) Ich wünsche Ihnen ein schönes Wochenende.
Marco smdm
Sie erwähnen nur eine Möglichkeit, tatsächliche Binärdaten zu schreiben stdout, die letzte.
Kotauskas