使用memoryview读取二进制文件



我在下面的代码中读取了一个具有特殊结构的大文件—其中两个块需要同时处理。我没有在文件中来回查找,而是将这两个块装入memoryview调用

with open(abs_path, 'rb') as bsa_file:
    # ...
    # load the file record block to parse later
    file_records_block = memoryview(bsa_file.read(file_records_block_size))
    # load the file names block
    file_names_block = memoryview(bsa_file.read(total_file_name_length))
    # close the file
file_records_index = names_record_index = 0
for folder_record in folder_records:
    name_size = struct.unpack_from('B', file_records_block, file_records_index)[0]
    # discard null terminator below
    folder_path = struct.unpack_from('%ds' % (name_size - 1),
        file_records_block, file_records_index + 1)[0]
    file_records_index += name_size + 1
    for __ in xrange(folder_record.files_count):
        file_name_len = 0
        for b in file_names_block[names_record_index:]:
            if b != 'x00': file_name_len += 1
            else: break
        file_name = unicode(struct.unpack_from('%ds' % file_name_len,
            file_names_block,names_record_index)[0])
        names_record_index += file_name_len + 1

文件被正确解析,但由于这是我第一次使用mamoryview接口,我不确定我做得对。file_names_block由以空结尾的c字符串组成。

  1. 是我的技巧file_names_block[names_record_index:]使用内存视图魔术还是我创建一些n^2片?这里需要使用islice吗?
  2. 如所见,我只是手动寻找空字节,然后继续unpack_from。但是我读到如何在python中将字节字符串分割成单独的字节,我可以在内存视图上使用cast()(文档?)-任何方法使用该(或其他技巧)以字节分割视图?我可以打给split('x00')吗?这会保持内存效率吗?

我希望你能告诉我正确的方法(在python 2中)

当涉及到以null结尾的字符串时,memoryview不会给您任何优势,因为它们除了固定宽度的数据之外没有任何设施。您也可以在这里使用bytes.split():

file_names_block = bsa_file.read(total_file_name_length)
file_names = file_names_block.split(b'0')

memoryview进行切片不会使用额外的内存(除了视图参数),但是如果使用强制转换,则在尝试访问序列中的元素时,会为解析的内存区域生成新的本机对象。

您仍然可以使用memoryview进行file_records_block解析;这些字符串以长度为前缀,使您有机会使用切片。在处理folder_path值时,只需保持内存视图的字节切片,不需要保持索引:

for folder_record in folder_records:
    name_size = file_records_block[0]  # first byte is the length, indexing gives the integer
    folder_path = file_records_block[1:name_size].tobytes()
    file_records_block = file_records_block[name_size + 1:]  # skip the null

因为memoryview来源于bytes对象,索引会给你一个字节的整数值,.tobytes()在给定的切片上给你一个新的bytes字符串,然后你可以继续切片,把剩下的留给下一个循环。

相关内容

  • 没有找到相关文章

最新更新