Travis Griggs wrote:
I'm writing some code that does a structured read from formatted binary file.
The code I came up with looks like:
# get the first four bytes, the first gap field
chunk = byteStream.read(4)
while chunk:
# interpret the gap bytes
gap, = struct.unpack('>I', chunk)
# suck off the valveCount
valveCount, = struct.unpack('>I', byteStream.read(4))
# collect the next valveCount signatures
signatures = [struct.unpack('>I', byteStream.read(4))[0] for _ in
range(valveCount)]
self.script.append(ScriptSpan(gap=gap, valveSet=signatures))
# now get the next 4 bytes for the gap of the next iteration, it'll be
empty if we're at end
chunk = byteStream.read(4)
I can't help but thinking that there's some better way (i.e. more pythonic) to
do this that doesn't involve having to use another module (Construct) or
exploring generators or something like that. What bugs me about it is that
there is two different styles for reading/decoding values from the byte stream.
valveCount and signatures are both paired invocations of unpack() and read().
But to detect the end of the stream (file), I have to split the read() and
unpack() of the gap value across 3 different lines of the code, and they don't
even sit adjacent to each other.
What do you have against generators? ;)
How about an iterator approach:
8<-------------------------------------------------------
class Gap_Valve_Reader(object): # untested
def __init__(self, filename):
self.byteStream = open(filename)
def __iter__(self):
return self
def __next__(self): # python 3 name
chunk = self.byteStream.read(8)
if not chunk:
self.byteStream.close()
raise StopIteration
gap, valveCount = struct.unpack('>II', chunk)
signatures = struct.unpack('>%sI' % valveCount,
self.byteStream.read(4 * valueCount))
return gap, signatures
next = __next__ # python 2 name
8<-------------------------------------------------------
then your main code can look like:
8<-------------------------------------------------------
gvr = Gap_Valve_Reader('binary_file.bin')
for gap, signatures in gvr:
self.script.append(ScriptSpan(gap=gap, valveSet=signatures))
8<-------------------------------------------------------
Don't forget to add error checking where appropriate.
~Ethan~
--
http://mail.python.org/mailman/listinfo/python-list