Elizabeth Finn wrote:
> I need to read a file that is in binary format, and then convert some of 
> the values into integer values. These values can range from 1 to 4 bytes.
>  
> First question – is there an easy way to do this? I finally wrote my own 
> little utility to handle multi-byte integers because I couldn’t find a 
> built-in way (except for ord() which works only for single bytes)

Alan suggested the struct module. It doesn't directly support 3-byte 
integers but perhaps you could pad them with a zero byte at the front. 
struct does let you unpack a whole string at once.

The Construct library is a higher-level interface to similar 
functionality. It doesn't seem to support 3-byte integers either but it 
is extensible.
>  
> def getnum(num_str):
>             """
>             Given a string representing a binary number, return the number.
>             If string is more than one byte, calculate the number to return.
>             Assume that each byte is signed magnitude
>             """                   
>             x = len(num_str)
>             ans = 0
>             for i in range( x ):
>                         nextstr = num_str[i:i+1]
>                         ans = ans * 256
>                         ans = ans + ord(nextstr)
>             return ans

Your loop could be written more simply as
for nextstr in num_str:
   ans = ans * 256
   ans = ans + ord(nextstr)

> This “brute force” method usually works, but - now here is the other 
> question -sometimes the code does not pick up two full bytes when it is 
> supposed to. I open the file and read a block that I want into a string:
>            
>                         f=open(fname, 'rb')
> f.seek(offset, 0)
> block = f.read(2000)
>  
> Then for each number I pull the bytes from the string, then call 
> getnum() to calculate the number.
>  
>             test = block[0:1]             # 1 byte
>             test = block[1:4]             # 3 bytes
>             test = block[4:6]             # 2 bytes
>             test = block[20:12]             # 2 bytes
>             test = block[1996:2000]       #4 bytes
>  
> This method usually works, except that for some of the 2-byte numbers I 
> get only the first byte and first half of the second byte – for 
> instance: 'x06\x33’ comes out as ‘x063’. This is very confusing 
> especially because one 2-byte substring – “00 01” comes out as expected, 
> but “06 52” becomes “065”. Any ideas?

It seems to work for me. I wonder if you are confused about the input 
you are giving it? Using your definition of getnum(), I get these results:
In [31]: getnum('\x06\x33')
Out[31]: 1587
In [33]: 6*256 + 0x33
Out[33]: 1587

In [34]: getnum('\x06\x52')
Out[34]: 1618
In [35]: 6*256 + 0x52
Out[35]: 1618

So it seems to be doing the right thing. Can you put
   print repr(test)
   print getnum(test)
into your test program and show us the results?

Kent
_______________________________________________
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor

Reply via email to