161

In python 2.x I could do this:

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

Now however, I get a TypeError: can't write bytes to text stream. Is there some secret encoding that I should use?

hiddensunset4
  • 5,825
  • 3
  • 39
  • 61
Ivan Baldin
  • 3,391
  • 3
  • 22
  • 14

4 Answers4

261

A better way:

import sys
sys.stdout.buffer.write(b"some binary data")
Benjamin Peterson
  • 19,297
  • 6
  • 32
  • 39
  • 4
    Using `sys.stdout.buffer` also lets you do things like using `shutil.copyfileobj` even when the source file object gives bytes, and not strings. +1 – csl Jun 19 '15 at 14:45
  • 1
    Programs using this can't be tested in IDLE 3: `AttributeError: 'PseudoOutputFile' object has no attribute 'buffer'` – Damian Yerrick May 18 '17 at 18:55
  • 5
    @DamianYerrick in IDLE (in Windows at least) `pythonw.exe` runs IDLE, which means that there is no stdout. It is emulated with tkinter. It physically can't handle bytes. In this case, `.decode('UTF-8', errors='replace')` your string, or run `python3 -I ` to get a REPL instead of using IDLE. – Artyer May 21 '17 at 11:41
  • 2
    Messes up order of writes when writing to `stderr` if using along with `print(file=sys.stderr)`. – Kotauskas Jul 19 '19 at 10:16
  • 1
    @Kotauskas are you calling flush after writing? – Myles Hollowed Apr 06 '21 at 21:18
  • buffer.flush() doesn't seems to work, no way to write unbuffered binary. – Vincent Alex Aug 03 '22 at 20:27
  • 3
    @VincentAlex ```sys.stdout.flush()``` – sivann Jan 18 '23 at 07:59
20

An idiomatic way of doing so, which is only available for Python 3, is:

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

The good part is that it uses the normal file object interface, which everybody is used to in Python.

Notice that I'm setting closefd=False to avoid closing sys.stdout when exiting the with block. Otherwise, your program wouldn't be able to print to stdout anymore. However, for other kind of file descriptors, you may want to skip that part.

Yajo
  • 5,808
  • 2
  • 30
  • 34
  • 2
    Why do you flush? Isn't it better to let Python decide when to flush stdout? – Martin Oct 20 '19 at 10:55
  • Can't the existing channel -- such as `sys.stdout` -- be somehow turned into binary mode (and then back) without opening a new one on top of it? – Mikhail T. Feb 19 '21 at 19:16
  • I don't think so. BTW I flush because otherwise the fd will be closed. Maybe python would flush anyways... you can try and report. – Yajo Mar 17 '21 at 13:08
  • 3
    `sys.stdout.buffer` is in binary mode – Marcel Nov 11 '21 at 13:13
  • "Notice that I'm setting closefd=False to avoid closing sys.stdout when exiting the with block. " Is it actually valid to re-open it when it's already open, though? – Karl Knechtel May 13 '22 at 20:16
17
import os
os.write(1, a.tostring())

or, os.write(sys.stdout.fileno(), …) if that's more readable than 1 for you.

tzot
  • 92,761
  • 29
  • 141
  • 204
Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • Thanks, that worked. Feels a bit hack-ish but I guess it's not that common thing to do. – Ivan Baldin May 25 '09 at 23:21
  • 10
    The problem with `os.write` is that you'll have to check the return value, as it doesn't guarantee that everything will be written. – mic_e Sep 01 '15 at 18:04
3

In case you would like to specify an encoding in python3 you can still use the bytes command like below:

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

where 1 is the corresponding usual number for stdout --> sys.stdout.fileno()

Otherwise if you don't care of the encoding just use:

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

If you want to use the os.write without the encoding, then try to use the below:

import os
os.write(1,b"Your string to Stdout\n")
Marco smdm
  • 1,020
  • 1
  • 15
  • 25
  • 1
    Programs using `os.write(sys.stdout.fileno(), some_bytes)` won't work in IDLE. `io.UnsupportedOperation: fileno` – Damian Yerrick May 18 '17 at 18:57
  • @DamianYerrick: You are right...the IDLE should not be used anyway to test something like that. Shortly: try to open the IDLE (I had the python3.5.1 shell) and simply import sys and sys.stdout.fileno() it will throw you io error, because in IDLE this is not supported operation :-) It is always important to remember in which environment you are working and try to get what is possible ;) Hope this clarify your query :-) Have a nice weekend. – Marco smdm May 19 '17 at 08:31
  • You only mention one way of writing actual binary data to `stdout`, the last one. – Kotauskas Jul 19 '19 at 10:18