จะเขียนข้อมูลไบนารีไปยัง stdout ใน python 3 ได้อย่างไร?


104

ใน python 2.x ฉันทำได้:

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

อย่างไรก็ตามตอนนี้ฉันได้รับไฟล์TypeError: can't write bytes to text stream. มีการเข้ารหัสลับบางอย่างที่ฉันควรใช้หรือไม่?


4
มันจะดีกว่ามากหากพบคำตอบที่ใช้ได้กับ Python
2.6+

2
os.writeจะทำงานได้ทั้งบน Py2 และ Py3
David Wolever

คำตอบ:


170

วิธีที่ดีกว่า:

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

4
การใช้sys.stdout.bufferยังช่วยให้คุณทำสิ่งต่างๆเช่นการใช้shutil.copyfileobjแม้ว่าออบเจ็กต์ไฟล์ต้นทางจะให้ไบต์และไม่ใช่สตริง +1
csl

1
โปรแกรมที่ใช้สิ่งนี้ไม่สามารถทดสอบได้ใน IDLE 3:AttributeError: 'PseudoOutputFile' object has no attribute 'buffer'
Damian Yerrick

4
@DamianYerrick ใน IDLE (อย่างน้อยใน Windows) pythonw.exeรัน IDLE ซึ่งหมายความว่าไม่มี stdout มันถูกเลียนแบบด้วย tkinter มันไม่สามารถจัดการกับไบต์ได้ ในกรณีนี้.decode('UTF-8', errors='replace')สตริงของคุณหรือเรียกใช้python3 -I <filename>เพื่อรับ REPL แทนที่จะใช้ IDLE
Artyer

messes ขึ้นคำสั่งของการเขียนเมื่อเขียนไปถ้าใช้พร้อมกับstderr print(file=sys.stderr)
Kotauskas

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

หรือos.write(sys.stdout.fileno(), …)หากอ่านได้ง่ายกว่า1สำหรับคุณ


ขอบคุณที่ได้ผล รู้สึกแฮ็คนิดหน่อย แต่ฉันคิดว่ามันไม่ใช่เรื่องธรรมดาที่จะทำ
Ivan Baldin

6
ปัญหาos.writeคือคุณจะต้องตรวจสอบมูลค่าที่ส่งคืนเนื่องจากไม่รับประกันว่าทุกอย่างจะเป็นลายลักษณ์อักษร
mic_e

11

วิธีที่เป็นสำนวนซึ่งมีเฉพาะใน Python 3 คือ:

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

ส่วนที่ดีคือมันใช้อินเตอร์เฟสไฟล์อ็อบเจ็กต์ปกติซึ่งทุกคนคุ้นเคยใน Python

สังเกตว่าฉันกำลังตั้งค่าที่closefd=Falseจะหลีกเลี่ยงการปิดsys.stdoutเมื่อออกจากwithบล็อก มิฉะนั้นโปรแกรมของคุณจะไม่สามารถพิมพ์ไปยัง stdout ได้อีกต่อไป อย่างไรก็ตามสำหรับตัวอธิบายไฟล์ประเภทอื่นคุณอาจต้องข้ามส่วนนั้นไป


จะล้างทำไม? ไม่ดีกว่าที่จะให้ Python ตัดสินใจว่าเมื่อใดที่จะล้าง stdout?
Martin

0

ในกรณีที่คุณต้องการระบุการเข้ารหัสใน python3 คุณยังสามารถใช้คำสั่ง bytes ดังต่อไปนี้:

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

โดยที่ 1 คือหมายเลขปกติที่สอดคล้องกันสำหรับ stdout -> sys.stdout.fileno ()

มิฉะนั้นหากคุณไม่สนใจการเข้ารหัสให้ใช้:

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

หากคุณต้องการใช้ os.write โดยไม่ต้องเข้ารหัสให้ลองใช้สิ่งต่อไปนี้:

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

1
โปรแกรมที่ใช้os.write(sys.stdout.fileno(), some_bytes)จะไม่ทำงานใน IDLE io.UnsupportedOperation: fileno
Damian Yerrick

@DamianYerrick: คุณพูดถูก ... ไม่ควรใช้ IDLE เพื่อทดสอบอะไรแบบนั้น สั้น ๆ : ลองเปิด IDLE (ฉันมี python3.5.1 เชลล์) และเพียงแค่นำเข้า sys และ sys.stdout.fileno () มันจะทำให้คุณเกิดข้อผิดพลาด io เนื่องจากใน IDLE ไม่รองรับการดำเนินการ :-) มันสำคัญเสมอ โปรดจำไว้ว่าคุณกำลังทำงานอยู่ในสภาพแวดล้อมใดและพยายามหาสิ่งที่เป็นไปได้;) หวังว่านี่จะเป็นการชี้แจงคำถามของคุณ :-) ขอให้มีความสุขในวันหยุดสุดสัปดาห์
Marco smdm

คุณพูดถึงวิธีเดียวในการเขียนข้อมูลไบนารีจริงstdoutวิธีสุดท้าย
Kotauskas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.