Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fastest way to unpack bits (sub-byte) numbers from file

Given a file with resolution-compressed binary data, I would like to convert the sub-byte bits into their integer representations in python. By this I mean I need to interpret n bits from a file as an integer.

Currently I am reading the file into bitarray objects, and am converting subsets of the objects into integers. The process works but is fairly slow and cumbersome. Is there a better way to do this, perhaps with the struct module?

import bitarray

bits = bitarray.bitarray()
with open('/dir/to/any/file.dat','r') as f:
    bits.fromfile(f,2) # read 2 bytes into the bitarray

    ## bits 0:4 represent a field
    field1 = int(bits[0:4].to01(), 2)  # Converts to a string of 0s and 1s, then int()s the string

    ## bits 5:7 represent a field
    field2 = int(bits[4:7].to01(), 2)

    ## bits 8:16 represent a field
    field3 = int(bits[7:16].to01(), 2)

print """All bits: {bits}\n\tfield1: {b1}={field1}\n\tfield2: {b2}={field2}\n\tfield3: {b3}={field3}""".format(
        bits=bits, b1=bits[0:4].to01(), field1=field1, 
        b2=bits[4:7].to01(), field2=field2,
        b3=bits[7:16].to01(), field3=field3)

Outputs:

All bits: bitarray('0000100110000000')
    field1: 0000=0
    field2: 100=4
    field3: 110000000=384
like image 556
zachd1_618 Avatar asked Mar 30 '16 16:03

zachd1_618


People also ask

How do I extract a bit from a number?

How to extract 'k' bits from a given position 'p' in a number? Examples: Input : number = 171 k = 5 p = 2 Output : The extracted number is 21 171 is represented as 10101011 in binary, so, you should get only 10101 i.e. 21.

How do you extract bits from a byte in Python?

*/ Step 1 : first convert the number into its binary form using bin(). Step 2 : remove the first two character. Step 3 : then extracting k bits from starting position pos from right.so, the ending index of the extracting substring is e=len(bi)-pos and starting index=e-k+1 Step 4 : extract k bit sub-string.

How many different states does and 8 bit byte have?

8-bit binary number (a byte) can have a value ranging from 0 (00000000 2) to 255 (11111111 2), that is 2 8 = 256 different combinations of bits forming a single 8-bit byte.

How do I get Python bits?

To find necessary bits to represent a number – we use "bit_length()" method of "int" class, it is called with an integer object and returns the total number of bits to require to store/represent an integer number in binary. Note: If the value is 0, bit_length() method returns 0.


1 Answers

This should work for your specific case:

#bitmasks of fields 1-3, they fit in 2 bytes
FIELD1 = 0b1111000000000000 # first 4 bits
FIELD2 = 0b0000111000000000 # next 3 bits
FIELD3 = 0b0000000111111111 # last 9 bits

def bytes_to_int(num):  #convert bytes object to an int
    res = 0
    num = num[::-1]  # reverse the bytes
    for i in range(len(num)):
        res += num[i] * (256**i)
    return res

def get_fields(f):
    chunk = bytes_to_int(f.read(2))  # read 2 bytes, f1-f3, convert to int
    f1 = (chunk & FIELD1) >> 12  # get each field with its bitmask
    f2 = (chunk & FIELD2) >> 9
    f3 = chunk & FIELD3
    f4 = f.read(f3)  # field4 as a bytes object

    return f1, f2, f3, f4

file = open('file.dat','rb')

#using your sample data
print(get_fields(file))  # returns 0, 4, 384, field4 as a bytes obj

file.close()
like image 105
SoreDakeNoKoto Avatar answered Sep 28 '22 00:09

SoreDakeNoKoto