Як записати двійкові дані до stdout в python 3?


103

У 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+ та 3.x
sorin

2
os.writeбуде працювати як на Py2, так і на Py3.
Девід Волвер

Відповіді:


169

Кращий спосіб:

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. Емулюється тинкіром. Він фізично не може обробляти байти. У цьому випадку, .decode('UTF-8', errors='replace')ваш рядок або запустіть, python3 -I <filename>щоб отримати REPL замість використання IDLE.
Artyer

Порушує порядок записів під час запису, stderrякщо використовується разом із print(file=sys.stderr).
Kotauskas

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

або, os.write(sys.stdout.fileno(), …)якщо це читабельніше, ніж 1для вас.


Дякую, що спрацювало. Відчуває трохи злому, але я думаю, що це не так часто.
Іван Балдін

6
Проблема os.writeполягає в тому, що вам доведеться перевірити значення повернення, оскільки це не гарантує, що все буде записано.
mic_e

10

Ідіоматичний спосіб зробити це, який доступний лише для 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?
Мартін

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 це не підтримується операція :-) Це завжди важливо пам'ятати, в якому середовищі ви працюєте, і спробувати отримати все можливе;) Сподіваюся, це уточнить ваш запит :-) Приємних вихідних.
Марко smdm

Ви згадуєте лише один спосіб запису фактичних бінарних даних stdout, останній.
Kotauskas
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.