7

既知の形式/構造のバイナリ ファイルがあります。

すべてのバイナリ データを構造体の配列に読み込むにはどうすればよいですか?

(疑似コードで)のようなもの

bytes = read_file(filename)
struct = {'int','int','float','byte[255]'}
data = read_as_struct(bytes, struct)
data[1]
>>> 10,11,10.1,Arr[255]

編集:

これまでの解決策:

data = []

fmt   = '=iiiii256i'
fmt_s = '=iiiii'
fmt_spec = '256i'

struct_size = struct.calcsize(fmt)

for i in range(struct_size, len(bytes)-struct_size, struct_size):
    dat1= list(struct.unpack(fmt_s, bytes[i-struct_size:i-1024]))
    dat2= list(struct.unpack(fmt_spec, bytes[i-1024:i]))
    dat1.append(dat2)
    data.append(dat1)
4

4 に答える 4

26

実際には、ファイルから構造体のリスト (または配列) を読み込もうとしているようです。Python でこれを行う慣用的な方法は、structモジュールを使用してループ内で呼び出すことですstruct.unpack()(ループの数が事前にわかっている場合は一定の回数、またはファイルの終わりに達するまで)。list. 後者の例を次に示します。

import struct

struct_fmt = '=5if255s' # int[5], float, byte[255]
struct_len = struct.calcsize(struct_fmt)
struct_unpack = struct.Struct(struct_fmt).unpack_from

results = []
with open(filename, "rb") as f:
    while True:
        data = f.read(struct_len)
        if not data: break
        s = struct_unpack(data)
        results.append(s)

リスト内包表記と短いジェネレーター関数ヘルパーを使用して、同じ結果をもう少し簡潔に取得することもできます(つまり、read_chunks()以下を参照)。

def read_chunks(f, length):
    while True:
        data = f.read(length)
        if not data: break
        yield data

with open(filename, "rb") as f:
    results = [struct_unpack(chunk) for chunk in read_chunks(f, struct_len)]

アップデート

実際、上記のようにヘルパー関数を明示的に定義する必要はありません。Python の組み込み関数を使用して、次のようにリスト内包表記自体で必要な反復子iter()オブジェクトを動的に作成できるためです。

from functools import partial

with open(filename, "rb") as f:
    results = [struct_unpack(chunk) for chunk in iter(partial(f.read, struct_len), b'')]
于 2013-01-08T14:10:29.793 に答える
15

structモジュールを使用します。そのライブラリに記載されている文字列形式で型を定義する必要があります。

struct.unpack('=HHf255s', bytes)

上記の例では、ネイティブのバイト順、2 つの unsigned short、float、および 255 文字の文字列が想定されています。

既に完全に読み取られたbytes文字列をループするにはitertools、 ;を使用します。私がここに適応させた便利なハタのレシピがあります:

from itertools import izip_longest, imap
from struct import unpack, calcsize

fmt_s = '=5i'
fmt_spec = '=256i'
size_s = calcsize(fmt_s)
size = size_s + calcsize(fmt_spec)

def chunked(iterable, n, fillvalue=''):
    args = [iter(iterable)] * n
    return imap(''.join, izip_longest(*args, fillvalue=fillvalue))

data = [unpack(fmt_s, section[:size_s]) + (unpack(fmt_spec, section[size_s:]),)
    for section in chunked(bytes, size)]
    

これにより、リストではなくタプルが生成されますが、必要に応じて調整するのは簡単です。

data = [list(unpack(fmt_s, section[:size_s])) + [list(unpack(fmt_spec, section[size_s:]))]
    for section in chunked(bytes, size)]
于 2013-01-08T13:12:46.943 に答える
1

コメントを追加

import struct 

最初にバイナリを配列に読み込むだけです

mbr = file('mbrcontent', 'rb').read() 

したがって、配列の一部を取得するだけです

partition_table = mbr[446:510] 

次に、整数として展開します

signature = struct.unpack('<H', mbr[510:512])[0] 

より複雑な例

little_endian = (signature == 0xaa55) # should be True 
print "Little endian:", little_endian 
PART_FMT = (little_endian and '<' or '>') + ( 
"B" # status (0x80 = bootable (active), 0x00 = non-bootable) 
# CHS of first block 
"B" # Head 
"B" # Sector is in bits 5; bits 9 of cylinder are in bits 7-6 
"B" # bits 7-0 of cylinder 
"B" # partition type 
# CHS of last block 
"B" # Head 
"B" # Sector is in bits 5; bits 9 of cylinder are in bits 7-6 
"B" # bits 7-0 of cylinder 
"L" # LBA of first sector in the partition 
"L" # number of blocks in partition, in little-endian format 
) 

PART_SIZE = 16 
fmt_size = struct.calcsize(PART_FMT) 
# sanity check expectations 
assert fmt_size == PART_SIZE, "Partition format string is %i bytes, not %i" % (fmt_size, PART_SIZE) 

def cyl_sector(sector_cyl, cylinder7_0): 
    sector = sector_cyl & 0x1F # bits 5-0 

    # bits 7-6 of sector_cyl contain bits 9-8 of the cylinder 
    cyl_high = (sector_cyl >> 5) & 0x03 
    cyl = (cyl_high << 8) | cylinder7_0 
    return sector, cyl 

#I have corrected the indentation, but the change is refused because less than 6 characters, so I am adding this useful comment.
for partition in range(4): 
    print "Partition #%i" % partition, 
    offset = PART_SIZE * partition 
    (status, start_head, start_sector_cyl, start_cyl7_0, part_type, end_head, end_sector_cyl, end_cyl7_0, 
    lba, blocks ) = struct.unpack( PART_FMT,partition_table[offset:offset + PART_SIZE]) 
    if status == 0x80: 
        print "Bootable", 
    elif status: 
        print "Unknown status [%s]" % hex(status), 
        print "Type=0x%x" % part_type 
        start = (start_head,) + cyl_sector(start_sector_cyl, start_cyl7_0) 
        end = (end_head,) + cyl_sector(end_sector_cyl, end_cyl7_0) 
        print " (Start: Heads:%i\tCyl:%i\tSect:%i)" % start 
        print " (End: Heads:%i\tCyl:%i\tSect:%i)" % end 
        print " LBA:", lba 
        print " Blocks:", blocks 
于 2013-01-08T13:18:47.250 に答える