Jak zapisywać dane binarne na stdout w Pythonie 3?


104

W pythonie 2.x mogłem to zrobić:

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

Teraz jednak otrzymuję plik TypeError: can't write bytes to text stream. Czy jest jakieś tajne kodowanie, którego powinienem użyć?


4
Znacznie lepiej byłoby znaleźć odpowiedź, która będzie działać z Pythonem 2.6+ i 3.x
sorin

2
os.writebędzie działać zarówno na Py2, jak i Py3.
David Wolever

Odpowiedzi:


170

Lepszy sposób:

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

4
Używanie sys.stdout.bufferpozwala również robić takie rzeczy, jak używanie, shutil.copyfileobjnawet jeśli obiekt pliku źródłowego podaje bajty, a nie łańcuchy. +1
csl

1
Programy korzystające z tego nie mogą być testowane w IDLE 3:AttributeError: 'PseudoOutputFile' object has no attribute 'buffer'
Damian Yerrick

4
@DamianYerrick w IDLE (przynajmniej w Windows) pythonw.exeuruchamia IDLE, co oznacza, że ​​nie ma standardowego wyjścia. Jest emulowany przez tkinter. Fizycznie nie obsługuje bajtów. W tym przypadku .decode('UTF-8', errors='replace')twój ciąg lub uruchom, python3 -I <filename>aby uzyskać REPL zamiast używać IDLE.
Artyer

Zepsuje kolejność zapisów podczas pisania do, stderrjeśli używasz razem z print(file=sys.stderr).
Kotauskas

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

lub, os.write(sys.stdout.fileno(), …)jeśli to jest bardziej czytelne niż 1dla Ciebie.


Dzięki, zadziałało. Czuje się trochę hakersko, ale wydaje mi się, że nie jest to powszechne.
Ivan Baldin

6
Problem os.writepolega na tym, że będziesz musiał sprawdzić zwracaną wartość, ponieważ nie gwarantuje to, że wszystko zostanie zapisane.
mic_e

11

Idiomatyczny sposób na zrobienie tego, który jest dostępny tylko dla Pythona 3, to:

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

Zaletą jest to, że używa normalnego interfejsu obiektu pliku, do którego wszyscy są przyzwyczajeni w Pythonie.

Zwróć uwagę, że ustawiam closefd=Falseunikanie zamykania sys.stdoutpodczas wychodzenia z withbloku. W przeciwnym razie Twój program nie będzie mógł już drukować na standardowe wyjście. Jednak w przypadku deskryptorów plików innego rodzaju możesz pominąć tę część.


Dlaczego się spłukujesz? Czy nie lepiej pozwolić Pythonowi zdecydować, kiedy opróżnić standardowe wyjście?
Martin

0

W przypadku, gdy chcesz określić kodowanie w python3, nadal możesz użyć polecenia bajtów, jak poniżej:

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

gdzie 1 jest odpowiednią zwykłą liczbą dla stdout -> sys.stdout.fileno ()

W przeciwnym razie, jeśli nie zależy Ci na kodowaniu, po prostu użyj:

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

Jeśli chcesz używać os.write bez kodowania, spróbuj użyć poniższego:

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

1
Programy używające os.write(sys.stdout.fileno(), some_bytes)nie będą działać w IDLE. io.UnsupportedOperation: fileno
Damian Yerrick

@DamianYerrick: Masz rację ... I tak nie należy używać IDLE do testowania czegoś takiego. Krótko: spróbuj otworzyć IDLE (miałem powłokę python3.5.1) i po prostu zaimportuj sys i sys.stdout.fileno () wyrzuci ci błąd io, ponieważ w IDLE nie jest to obsługiwana operacja :-) Zawsze jest ważne zapamiętać, w jakim środowisku pracujesz i spróbować uzyskać to, co jest możliwe;) Mam nadzieję, że to wyjaśni Twoje pytanie :-) Miłego weekendu.
Marco smdm

Wspomina się tylko o jednym sposobie zapisywania rzeczywistych danych binarnych stdout, ostatnim.
Kotauskas
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.