error writing str to binary stream - fails in Python 3.0.1, works in2.x

W

wallenpb

I am working with a bit of code that works ok in Python 2.x (tested
fine in 2.5.4 and 2.6.1) but fails in 3.0.1.
The code opens a file for binary output to witht the objective to
produce a .bmp graphics file. The code below illustrates the first of
several like errors when a str object is attempted to be written to
the binary file. From what I have seen, this was a fairly common
technique prior to 3.0.1 being released so I am assuming the type
checking is tighter with the new version. What is the proper way of
doing this now, or the work around? Any help appreciated. -- Bill

the code:
-----------------------------------
self.out=open(filename,"wb")
self.out.write("BM") # magic number



This the is the error output from Python:
------------------------------------
Traceback (most recent call last):
File "py_mandel.py", line 19, in <module>
my_bmp=kohn_bmp("out.bmp",image_width,image_height,3)
File "C:\Python30\py_kohn_bmp.py", line 47, in __init__
self.out.write("BM") # magic number
File "C:\Python30\lib\io.py", line 1038, in write
raise TypeError("can't write str to binary stream")
TypeError: can't write str to binary stream
 
R

R. David Murray

I am working with a bit of code that works ok in Python 2.x (tested
fine in 2.5.4 and 2.6.1) but fails in 3.0.1.
The code opens a file for binary output to witht the objective to
produce a .bmp graphics file. The code below illustrates the first of
several like errors when a str object is attempted to be written to
the binary file. From what I have seen, this was a fairly common
technique prior to 3.0.1 being released so I am assuming the type
checking is tighter with the new version. What is the proper way of
doing this now, or the work around? Any help appreciated. -- Bill

the code:
-----------------------------------
self.out=open(filename,"wb")
self.out.write("BM") # magic number



This the is the error output from Python:
------------------------------------
Traceback (most recent call last):
File "py_mandel.py", line 19, in <module>
my_bmp=kohn_bmp("out.bmp",image_width,image_height,3)
File "C:\Python30\py_kohn_bmp.py", line 47, in __init__
self.out.write("BM") # magic number
File "C:\Python30\lib\io.py", line 1038, in write
raise TypeError("can't write str to binary stream")
TypeError: can't write str to binary stream

In 3.x the 'str' type is unicode. If you want to work with binary byte
streams, you want to use the 'bytes' type. Bytes contstants are
written with a leading 'b', so the code snipped above would become

self.out.write(b'BM')
 
W

wallenpb

In 3.x the 'str' type is unicode.  If you want to work with binary byte
streams, you want to use the 'bytes' type.  Bytes contstants are
written with a leading 'b', so the code snipped above would become

    self.out.write(b'BM')
David,
Thanks for the assist. One more question, please.

self.out.write(b'BM') worked beautifully. Now I also have a similar
issue, for instance:
self.out.write("%c" % y) is also giving me the same error as the other
statement did.
I tried self.out.write(bytes("%c" %y),encoding=utf-8) in an attempt to
convert to bytes, which it did, but not binary. How do I affect
self.out.write("%c" % y) to write out as a binary byte steam? I also
tried self.out.write(b"%c" % y), but b was an illegal operator in when
used that way.
It is also supposed to be data being written to the .bmp file. --Bill
 
B

Benjamin Peterson

self.out.write(b'BM') worked beautifully. Now I also have a similar
issue, for instance:
self.out.write("%c" % y) is also giving me the same error as the other
statement did.
I tried self.out.write(bytes("%c" %y),encoding=utf-8) in an attempt to
convert to bytes, which it did, but not binary. How do I affect
self.out.write("%c" % y) to write out as a binary byte steam? I also
tried self.out.write(b"%c" % y), but b was an illegal operator in when
used that way.
It is also supposed to be data being written to the .bmp file. --Bill

Are you writing to sys.stdout? If so, use sys.stdout.buffer.write(b'some
bytes'). If you're writing to a file, you have to open it in binary mode like
this: open("someimage.bmp", "wb")
 
W

wallenpb

 <wallenpb <at> gmail.com> writes:




Are you writing to sys.stdout? If so, use sys.stdout.buffer.write(b'some
bytes'). If you're writing to a file, you have to open it in binary mode like
this: open("someimage.bmp", "wb")

Yes, I am writing to a file. That portion is correct and goes like
this:
self.out=open(filename,"wb")
self.out.write(b"BM") # This line works thanks to advice
given in previous reply

However, here is some more code that is not working and the error it
gives:
def write_int(self,n):
str_out='%c%c%c%c' % ((n&255),(n>>8)&255,(n>>16)&255,(n>>24)&255)
self.out.write(str_out) #this is line 29, does not work - not
sure how to get this complex str converted over to binary bytes to
write to bmp file.
#tried to use self.out.write(bytes
("blah", encoding='utf-8')) type coding here. This way ran without
error, but
#did not write proper data to the .bmp
file.In hex editor it was obvious it was filling in wrong bits.
#Also tried self.out.write(b'%c%c%c%c' %
(blah)) but this gave errors for bad operands for % operator.
---------------------
Traceback (most recent call last):
File "C:\Python30\py_kohn_bmp.py", line 29, in write_int
self.out.write(str_out)
File "C:\Python30\lib\io.py", line 1038, in write
raise TypeError("can't write str to binary stream")
TypeError: can't write str to binary stream
 
T

Terry Reedy

Thanks for the assist. One more question, please.

self.out.write(b'BM') worked beautifully. Now I also have a similar
issue, for instance:
self.out.write("%c" % y) is also giving me the same error as the other
statement did.
I tried
self.out.write(bytes("%c" %y),encoding=utf-8)
in an attempt to convert to bytes, which it did, but not binary.

If you actually wrote that, try

self.out.write(bytes("%c" %y,encoding=utf-8))

To aid respondents, copy an paste actually code run and actual result or
traceback received.

tjr
 
R

R. David Murray

Yes, I am writing to a file. That portion is correct and goes like
this:

self.out=open(filename,"wb")
self.out.write(b"BM") # This line works thanks to advice given
# in previous reply

However, here is some more code that is not working and the error it
gives:

def write_int(self,n):
str_out='%c%c%c%c' % ((n&255),(n>>8)&255,(n>>16)&255,(n>>24)&255)
self.out.write(str_out)

this is line 29, does not work - not
sure how to get this complex str converted over to binary bytes to
write to bmp file.

(I reformatted your message slightly to make the code block stand out more.)

A byte array is an array of bytes, and it understands integers as input.
Check out the PEP (the official docs leave some things out):

http://www.python.org/dev/peps/pep-0358/

Here is some example code that works:

out=open('temp', "wb")
out.write(b"BM")

def write_int(out, n):
bytesout=bytes(([n&255), (n>>8)&255, (n>>16)&255, (n>>24)&255])
out.write(bytesout)

write_int(out, 125)
 
J

John Machin

(I reformatted your message slightly to make the code block stand out more.)

A byte array is an array of bytes, and it understands integers as input.
Check out the PEP (the official docs leave some things out):

   http://www.python.org/dev/peps/pep-0358/

Here is some example code that works:

No it doesn't. There is an extra "(" in the assignment to bytesout.
    out=open('temp', "wb")
    out.write(b"BM")

    def write_int(out, n):
        bytesout=bytes(([n&255), (n>>8)&255, (n>>16)&255, (n>>24)&255])
        out.write(bytesout)  

    write_int(out, 125)

Consider using the struct module; it's expressly designed for that
sort of thing.

import struct
out.write(struct.pack("<2sI", "BM", 125))

HTH,
John
 
W

wallenpb

(I reformatted your message slightly to make the code block stand out more.)
A byte array is an array of bytes, and it understands integers as input..
Check out the PEP (the official docs leave some things out):
Here is some example code that works:

No it doesn't. There is an extra "(" in the assignment to bytesout.


    out=open('temp', "wb")
    out.write(b"BM")
    def write_int(out, n):
        bytesout=bytes(([n&255), (n>>8)&255, (n>>16)&255, (n>>24)&255])
        out.write(bytesout)  
    write_int(out, 125)

Consider using the struct module; it's expressly designed for that
sort of thing.

import struct
out.write(struct.pack("<2sI", "BM", 125))

HTH,
John

To everyone who has responded, thanks very much. This was an effort
to port some 2.x code to 3.0.1. It is obvious now that just a couple
of tweaks will not do it. I need to step back and give the code a
good reevaluation. Thanks for all the great pointers! I learned a
lot. :)

---Bill
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,165
Latest member
JavierBrak
Top