Python 使用memoryview读取二进制文件

Python 使用memoryview读取二进制文件,python,python-2.7,binaryfiles,memoryview,Python,Python 2.7,Binaryfiles,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

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

  • 我的技巧是使用memoryview魔术的
    文件\u名称\u块[名称\u记录\u索引:
    ,还是创建一些n^2个切片?我需要在这里使用
    islice
  • 如图所示,我只是手动查找空字节,然后继续从解包。但是我读到,我可以在内存视图上使用
    cast()
    (docs?)——有没有办法用它(或其他技巧)将视图拆分为字节?我可以调用
    split('\x00')
    ?这会保持内存效率吗

  • 我希望您能深入了解一种正确的方法(在python 2中)。

    A
    memoryview
    在处理以空结尾的字符串时不会给您带来任何好处,因为它们除了固定宽度的数据之外没有任何功能。您也可以在此处使用
    bytes.split()

    file_names_block = bsa_file.read(total_file_name_length)
    file_names = file_names_block.split(b'\00')
    
    切片
    memoryview
    不会使用额外的内存(视图参数除外),但如果使用强制转换,则在尝试访问序列中的元素时,会为解析的内存区域生成新的本机对象

    您仍然可以使用
    memoryview
    进行
    文件\记录\块
    解析;这些字符串以长度作为前缀,使您有机会使用切片。只需在处理
    文件夹路径
    值时对内存视图的字节进行切片,就无需保留索引:

    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
    字符串,然后,您可以继续切片,将剩余部分留给下一个循环。

    我不认为MemoryView在这里给您带来任何东西;内存视图,如
    struct
    模块,对于以空结尾的字符串没有特定的功能。确实谢谢:)我想我可以使用split然后添加
    del file\u names\u block
    。至于我认为应该是的,是不是应该是
    file\u records\u block[name\u size:][/code>?我想知道在最后一次操作之后(底层缓冲区的)内存被释放的速度有多快,但这是给c组的:)@Mr_和_Mrs_D:你可以在循环后使用
    文件记录块.release()
    来释放
    字节
    对象。@Mr_和_Mrs_D:我不确定你对
    文件记录块[name\u size:]
    不过..oooooo ps-文件记录块[name\u size+1:]抱歉午睡!总之,你认为我的方法能给我带来什么吗?这是读取结构化二进制文件的好方法吗?@Mr_和Mrs_D:啊,当时误解了那里的结构。我认为它们是Pascal字符串(单字节长度前缀,然后字符串值为length-1字节)。然后必须在
    name\u size+1
    处切片下一个块。