Python 在二进制文件中的特定字节上循环

Python 在二进制文件中的特定字节上循环,python,Python,我想在二进制文件中找到具有特定字节的点。例如,假设我想检查文件中以两个字节开头的所有实例: AB C3 并以两个字节结束: AB C4 现在我正在做 while True: byte = file.read(1) if not byte: break if ord(byte) == 171: 但是,我将如何继续循环,以便一旦我找到第一个AB-我将看到连续的下一个字节是C3。然后,一旦我找到C3,我将如何读取字节来

我想在二进制文件中找到具有特定字节的点。例如,假设我想检查文件中以两个字节开头的所有实例:

AB C3

并以两个字节结束:

AB C4

现在我正在做

    while True:
        byte = file.read(1)
         if not byte:
           break
         if ord(byte) == 171:
但是,我将如何继续循环,以便一旦我找到第一个AB-我将看到连续的下一个字节是C3。然后,一旦我找到C3,我将如何读取字节来循环,直到序列AB C4(如果存在)为止,而不会弄乱我的整体循环结构

我遇到了困难,因为我不知道如何处理python的read和seek函数。当我找到序列时,我是否应该保留一个指针来查找?有没有一种简单的方法来完成我在python中尝试做的事情,而我只是不知道


谢谢

假设您可以将整个文件读入内存:

import re
import operator

with open(filename, 'rb') as file:
    bytes = file.read()

matches = [(i.start(),i.end())
            for i in re.finditer(b'\xab\xc3*\xab\xc3', bytes)]
中匹配的每个元组包含一个开始索引和停止索引(使用切片表示法,其中停止索引是最后的
c3
字节后的一个索引位置)。这些切片都是不重叠的

如果需要所有重叠匹配项的索引,则需要沿以下行变换
匹配项

overlapping = [(start, stop) 
                  for start in map(operator.itemgetter(0), matches)
                  for stop in map(operator.itemgetter(1), matches)
                      if start < stop]
重叠=[(开始、停止) 对于map中的start(operator.itemgetter(0),匹配) 对于地图中的停止(操作符.itemgetter(1),匹配) 如果开始<停止]
如果您负担不起将整个文件读入内存的费用,您可以通过迭代字节来完成。我将a用作辅助数据结构,利用
maxlen
参数扫描每一个连续的字节对。为了让我使用for循环而不是容易出错的while循环,我使用来逐字节迭代文件。例如
iter(iterable,sentinal)
首先让我们构建一个测试用例:

>>> import io, functools
>>> import random
>>> some_bytes = bytearray([random.randint(0, 255) for _ in range(12)] + [171, 195] + [88, 42, 88, 42, 88, 42] + [171, 196]+[200, 211, 141])
>>> some_bytes
bytearray(b'\x80\xc4\x8b\x86i\x88\xba\x8a\x8b\x07\x9en\xab\xc3X*X*X*\xab\xc4\xc8\xd3\x8d')
>>>
现在,我们来讨论一下:

>>> from collections import deque
>>> start = deque([b'\xab', b'\xc3'])
>>> stop = deque([b'\xab', b'\xc4'])
>>> current = deque(maxlen=2)
>>> target = []
>>> inside = False
让我们假设正在读取文件:

>>> f = io.BytesIO(some_bytes)
现在,创建方便的逐字节iterable:

>>> read_byte = functools.partial(f.read, 1)
现在我们可以更轻松地循环:

>>> for b in iter(read_byte, b''):
...     current.append(b)
...     if not inside and current == start:
...         inside = True
...         continue
...     if inside and current == stop:
...         break
...     if inside:
...         target.append(b)
...
>>> target
[b'X', b'*', b'X', b'*', b'X', b'*', b'\xab']
>>>
您会注意到,这里保留了“end”的第一个值。不过,清理工作很简单。下面是一个更加充实的示例,其中分隔符之间有几个字节的“运行”:

>>> some_bytes = some_bytes * 3
>>> start = deque([b'\xab', b'\xc3'])
>>> stop = deque([b'\xab', b'\xc4'])
>>> current = deque(maxlen=2)
>>> targets = []
>>> target = []
>>> inside = False
>>> f = io.BytesIO(some_bytes)
>>> read_byte = functools.partial(f.read, 1)
>>> for b in iter(read_byte, b''):
...     current.append(b)
...     if not inside and current == start:
...         inside = True
...         continue
...     if inside and current == stop:
...         inside = False
...         target.pop()
...         targets.append(target)
...         target = []
...     if inside:
...         target.append(b)
...
b'\xab'
b'\xab'
b'\xab'
>>> targets
[[b'X', b'*', b'X', b'*', b'X', b'*'], [b'X', b'*', b'X', b'*', b'X', b'*'], [b'X', b'*', b'X', b'*', b'X', b'*']]
>>>
这种方法比将文件读入内存并使用
re
要慢,但会节省内存。可能会有一些我没有想到的边缘情况需要处理,但我认为扩展上述方法应该很简单。此外,如果存在一个“开始”字节序列,但没有相应的“停止”,则
目标
列表将持续增长,直到文件耗尽

最后,也许最好的方法是以可管理的块读取文件,并使用下面的逻辑处理这些块。这结合了空间和时间效率。在伪代码中:

chunksize = 1024
start = deque([b'\xab', b'\xc3'])
stop = deque([b'\xab', b'\xc4'])
current = deque(maxlen=2)
targets = []
target = []
inside = False
read_chunk = functools.partial(f.read, chunksize)

for bytes_chunk in iter(read_chunk, b''):
    for b in bytes_chunk:
        < same logic as above >
chunksize=1024
start=deque([b'\xab',b'\xc3'])
stop=deque([b'\xab',b'\xc4']))
电流=deque(最大值=2)
目标=[]
目标=[]
内=假
read\u chunk=functools.partial(f.read,chunksize)
对于iter中的字节块(读取块,b“”):
对于字节中的b\u块:
<与上述逻辑相同>

< /代码>文件有多大(即将其完全读入内存是可行的)吗?此外,你是否考虑过做“代码> GRP-AOB”\xAb\xC4“< /代码>”?你使用的是什么版本的Python?你可以使用正则表达式来做它。看见