Bagaimana cara menulis data biner ke stdout di python 3?

103

Di python 2.x saya bisa melakukan ini:

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

Namun sekarang, saya mendapatkan file TypeError: can't write bytes to text stream. Apakah ada pengkodean rahasia yang harus saya gunakan?

Ivan Baldin
sumber
4
Akan jauh lebih baik untuk menemukan jawaban yang akan bekerja dengan Python 2.6+ dan 3.x
sorin
2
os.writeakan bekerja pada Py2 dan Py3.
David Wolever

Jawaban:

169

Cara yang lebih baik:

import sys
sys.stdout.buffer.write(b"some binary data")
Benjamin Peterson
sumber
4
Menggunakan sys.stdout.bufferjuga memungkinkan Anda melakukan hal-hal seperti menggunakan shutil.copyfileobjbahkan ketika objek file sumber memberikan byte, dan bukan string. +1
csl
1
Program yang menggunakan ini tidak dapat diuji di IDLE 3:AttributeError: 'PseudoOutputFile' object has no attribute 'buffer'
Damian Yerrick
4
@DamianYerrick di IDLE (setidaknya di Windows) pythonw.exemenjalankan IDLE, yang berarti tidak ada stdout. Ini ditiru dengan tkinter. Secara fisik tidak dapat menangani byte. Dalam hal ini, .decode('UTF-8', errors='replace')string Anda, atau jalankan python3 -I <filename>untuk mendapatkan REPL daripada menggunakan IDLE.
Artyer
Mengacaukan urutan penulisan saat menulis stderrjika menggunakan bersama print(file=sys.stderr).
Kotauskas
15
import os
os.write(1, a.tostring())

atau, os.write(sys.stdout.fileno(), …)jika itu lebih mudah dibaca daripada 1Anda.

Alex Martelli
sumber
Terima kasih, itu berhasil. Rasanya agak hack-ish tapi saya rasa itu bukan hal yang umum untuk dilakukan.
Ivan Baldin
6
Masalahnya os.writeadalah Anda harus memeriksa nilai pengembalian, karena tidak menjamin bahwa semuanya akan ditulis.
mic_e
10

Cara idiomatis untuk melakukannya, yang hanya tersedia untuk Python 3, adalah:

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

Bagian yang baik adalah ia menggunakan antarmuka objek file normal, yang semua orang terbiasa dengan Python.

Perhatikan bahwa saya mengatur closefd=Falseuntuk menghindari penutupan sys.stdoutsaat keluar dari withblok. Jika tidak, program Anda tidak akan dapat mencetak ke stdout lagi. Namun, untuk jenis deskriptor file lainnya, Anda mungkin ingin melewatkan bagian itu.

Yajo
sumber
Mengapa Anda memerah? Bukankah lebih baik membiarkan Python memutuskan kapan harus melakukan flush stdout?
Martin
0

Jika Anda ingin menentukan pengkodean dalam python3, Anda masih dapat menggunakan perintah byte seperti di bawah ini:

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

di mana 1 adalah nomor biasa yang sesuai untuk stdout -> sys.stdout.fileno ()

Sebaliknya, jika Anda tidak peduli dengan pengkodean, gunakan saja:

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

Jika Anda ingin menggunakan os.write tanpa pengkodean, coba gunakan yang di bawah ini:

import os
os.write(1,b"Your string to Stdout\n")
Marco smdm
sumber
1
Program yang menggunakan os.write(sys.stdout.fileno(), some_bytes)tidak akan bekerja di IDLE. io.UnsupportedOperation: fileno
Damian Yerrick
@DamianYerrick: Anda benar ... IDLE seharusnya tidak digunakan untuk menguji sesuatu seperti itu. Singkatnya: coba buka IDLE (saya punya shell python3.5.1) dan cukup impor sys dan sys.stdout.fileno () itu akan membuat Anda io error, karena dalam IDLE ini tidak didukung operasi :-) Itu selalu penting untuk mengingat di lingkungan mana Anda bekerja dan mencoba untuk mendapatkan apa yang mungkin;) Semoga ini menjelaskan pertanyaan Anda :-) Selamat berakhir pekan.
Marco smdm
Anda hanya menyebutkan satu cara untuk menulis data biner yang sebenarnya ke stdout, yang terakhir.
Kotauskas