Search code examples
pythonstructunpack

Python struct unpacking integer followed by double


I am trying to unpack a struct from a binary file and I know that the first 4 bytes are an integer (with value 64) and the next 3*8 bytes are three doubles. I have stored the data in a vector called fileContent like this:

with open('data', mode='rb') as file: 
    fileContent = file.read()

Then I try:

print(struct.unpack("i", fileContent[0:4]))

and this correctly prints the number 64. However, I would like to also read the following double so I modify the statement above to

print(struct.unpack("id", fileContent[0:12]))

(since the integer should be 4 bytes and the double should be 8, yielding a total of 12 bytes). However, I get an error saying that

struct.error: unpack requires a bytes object of length 16

Also, if I try to read the double only and use:

print(struct.unpack("d", fileContent[4:12]) 

I do not get the correct value of the double! Changing the slicing above to [8:16] gives the correct value. Can someone please explain this? I know for sure that the first 4 bytes in the file should be an integer and the next 8 should be a double. Does read() somehow pad the integer with zeroes, or what is going on?


Solution

  • The unpack() will automatically do padding for you. So unpack('id', …) will pad the integer to 8 bytes, that's why you're getting the "struct.error: unpack requires a bytes object of length 16" error.

    It can easily be seen like this:

    >>> pack('id', 42, 42)
    b'*\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E@'
    

    But the fix is easy, as you know the endianness of the file, you should specify it, and by specifing it, padding will be disabled:

    >>> unpadded = pack('>id', 42, 42)
    >>> len(unpadded)
    12
    >>> unpack('>id', unpadded)
    (42, 42.0)