FWIW, you should use read(2) , not readline(2) . And if the fmt line is really equal to '>' , you should not get this error. Here is a short demo that works as expected.
from struct import unpack fname = 'qbytes'
Output
0 1 1 1 258 258 2 515 515 3 772 772 4 1029 1029 5 1286 1286 6 1543 1543 7 1800 1800 8 2057 2057 9 2314 2314 10 2571 2571 11 2828 2828 12 3085 3085 13 3342 3342 14 3599 3599 15 3856 3856
BTW, struct.unpack() always returns a tuple, even if the return value is a single element.
Using readline(2) in a binary may give unexpected results. In my test file in the above code there is (in Linux style) a new line \xa0 in the file. Therefore, if you change s = fid.read(2) to s = fid.readline(2) , everything works fine at first, but on line 10 it crashes because it only reads one byte because of this new line char:
from struct import unpack fname = 'qbytes'
Output
0 '\x00\x01' 1 1 1 '\x01\x02' 258 258 2 '\x02\x03' 515 515 3 '\x03\x04' 772 772 4 '\x04\x05' 1029 1029 5 '\x05\x06' 1286 1286 6 '\x06\x07' 1543 1543 7 '\x07\x08' 1800 1800 8 '\x08\t' 2057 2057 9 '\t\n' 2314 2314 10 '\n' Traceback (most recent call last): File "./qtest.py", line 30, in <module> print i, ReadWord(fid, '>', addr), n File "./qtest.py", line 22, in ReadWord s = unpack(fmt + 'h', s) struct.error: unpack requires a string argument of length 2
P.S.
You have several functions in your code that almost do the same. This violates the DRY principle: do not repeat yourself. Here is one way to fix this using the partial function application. For more information, see functools docs .
from functools import partial def ReadNumber(fid, datalen=1, fmt='>', conv='b', addr=0): fid.seek(addr) s = fid.read(datalen) if len(s) != datalen: raise IOError('Read %d bytes but expected %d at %d' % (len(s), datalen, addr)) return unpack(fmt+conv, s)[0] ReadByte = partial(ReadNumber, datalen=1, conv='b') ReadWord = partial(ReadNumber, datalen=2, conv='h') ReadLong = partial(ReadNumber, datalen=4, conv='l') ReadFloat = partial(ReadNumber, datalen=4, conv='f') ReadDouble = partial(ReadNumber, datalen=8, conv='d')
To call these new functions you need to use keywords. For instance,
ReadLong(fid, fmt='>', addr=addr)
True, this is a little longer, but it makes the code a little more readable.