2016-03-30 13 views
5

解像度が圧縮されたバイナリデータを持つファイルで、私はサブバイトのビットをPythonの整数表現に変換したいと思います。これにより、ファイルからのビットを整数として解釈する必要があることを意味します。ファイルからビット(サブバイト)番号を解凍する最速の方法

現在、ファイルをbitarray個のオブジェクトに読み込み、オブジェクトのサブセットを整数に変換しています。プロセスは機能しますが、かなり遅くて面倒です。おそらくstructモジュールを使用して、これを行うより良い方法はありますか?

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) 

出力:

All bits: bitarray('0000100110000000') 
    field1: 0000=0 
    field2: 100=4 
    field3: 110000000=384 
+0

フィールドのサイズは、ファイルを通過するときに繰り返されるのか、まったくランダムなのですか。彼らはバイト境界を越えますか? –

+0

1.フィールドは、バイト境界を越えて動作します。 2.フィールドは繰り返されますが、動的に読み込まなければならない未知のサイズのチャンクがあります。 I.私の例では、 'field3'はどのくらい大きな' field4'が必要であるかを教えてくれます。次に、ファイルは 'field1'、' field2'などを繰り返します。 –

+0

はフィールド4のサイズ(バイトまたはビット)ですか?すべてが整数に収まる必要がありますか? – TisteAndii

答えて

2

これはあなたの特定のケースのために働く必要があります。

#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 
    f4 = bytes_to_int(f4) #comment this line if you want field4 as a bytes obj 

    return f1, f2, f3, f4 

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

#using your sample data 
print(get_fields(file)) # returns 0, 4, 384, field4 as an int 

file.close() 

structモジュールを使用することもできましたが、それは384バイト長であるあなたのFIELD4のために必要とされるであろうint型、に8バイト以上を展開カント。

+0

を参照してください。 'int.from_bytes'には良い言及があります。残念ながら私は2.7を実行しています。これは私が探しているものです –

+0

@ zachd1_618 ok ...私はそれを修正することができます...ファイルをテキストまたはrawバイト形式で読み込んでいますか?テキストが1と0の場合、int(n、2)は変換を実行できます。また、フィールド4はバイトであり、バイト境界を越えないので、フィールド1-3のみがサブバイトレベルにあり、それらはすべて2バイトに収まると言うのは正しいですか? – TisteAndii

+0

私は生のバイトでファイルを読んでいます。あなたの例と同じように 'file.read(num_bytes)'。そして確かに、未知のサイズの 'field4'はバイト全体にあり、バイト境界を越えていないと言っても間違いありません。 –

4

あなたが誰かのモジュールを使用して[OK]をしている場合はビット列のモジュールは、ビットの優れた表現と操作持っているように、それが見えます:例えばhttp://pythonhosted.org/bitstring/index.html

をあなたが知っていれば、フォーマット文字列を使用できるフィールドのサイズ: http://pythonhosted.org/bitstring/reading.html#reading-using-format-strings

import bitstring 
bitstream = bitstring.ConstBitStream(filename='testfile.bin') 
field1, field2, field3 = bitstream.readlist('int:4, int:3, int:9') 

あなたのフィールドを知らなかった場合は、あなたがすべてのビットを読み込み、その後、すべてのフィールドを抽出するためにスライスし使用することができますサイズ:http://pythonhosted.org/bitstring/slicing.html

import bitstring 
bitstream = bitstring.ConstBitStream(filename='testfile.bin') 
bits = bitstring.BitArray(bitstream) 
field1 = bits[0:4].int 
field2 = bits[4:7].int 
field3 = bits[7:16].int 

だけの思考、あなたはおそらくすでにこのモジュールを見つけました。

+0

ああ、署名された使用の代わりに符号なしを使用する場合は、 – pmartin

関連する問題