用memoryvi读取二进制文件

2024-06-09 12:45:16 发布

您现在位置:Python中文网/ 问答频道 /正文

我在下面的代码中读到了一个大文件,它有一个特殊的结构-其中有两个块需要同时处理。我没有在文件中来回搜索,而是加载了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接口,所以我不确定是否正确地执行了它。文件\u names_块由以null结尾的c字符串组成。在

  1. 我的技巧是file_names_block[names_record_index:]使用memoryview魔术还是创建一些n^2个切片?我需要在这里使用islice吗?在
  2. 如前所示,我只需手动查找空字节,然后继续执行unpack_from。但我在How to split a byte string into separate bytes in python中读到我可以使用cast()(docs?)在内存视图上-有什么方法可以使用这个(或其他技巧)将视图拆分为字节?我能打电话给split('\x00')吗?这样能保持内存效率吗?在

我将非常感谢您对实现这一目标的正确方法的见解(在Python2中)。在


Tags: 文件nameinfromsizeindexlennames
1条回答
网友
1楼 · 发布于 2024-06-09 12:45:16

当涉及到以null结尾的字符串时,memoryview不会给您带来任何好处,因为它们除了固定宽度的数据之外没有其他任何功能。您不妨在此处使用bytes.split()

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

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

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

^{pr2}$

因为memoryview源于bytes对象,索引将给您一个字节的整数值,.tobytes()在给定切片上为该节提供一个新的bytes字符串,然后您可以继续切片,将剩余部分留给下一个循环。在

相关问题 更多 >