我想在二进制文件中找到具有特定字节的点。例如,我想检查我的文件中以两个字节开头的所有实例:
AB C3
以两个字节结束:
AB C4
现在我正在做
while True:
byte = file.read(1)
if not byte:
break
if ord(byte) == 171:
但是接下来我将如何继续循环以便一旦找到第一个AB-我将看到连续的下一个字节是C3。然后,一旦我找到C3,我将如何读取字节循环直到序列AB C4(如果存在)而不会弄乱我的整体循环结构。
我遇到了困难,因为我不确定如何处理python的读取和搜索功能。当我找到序列时,我应该保留一个指针来寻找吗?有没有一种简单的方法来做我在python中尝试做的事情,我只是不知道?
感谢。
答案 0 :(得分:0)
假设您可以将整个文件读入内存:
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)]
matches
中的每个元组都包含一个起始索引和停止索引(使用切片表示法,其中停止索引是最后c3
个字节后的一个索引位置)。切片都是不重叠的。
如果您想要所有重叠匹配的索引,则需要按以下方式转换matches
:
overlapping = [(start, stop)
for start in map(operator.itemgetter(0), matches)
for stop in map(operator.itemgetter(1), matches)
if start < stop]
答案 1 :(得分:0)
好吧,如果你不能把整个文件读入内存,你可以通过遍历字节来完成这个。我使用deque
作为辅助数据结构,利用maxlen
参数扫描每个连续的字节对。为了让我使用for循环而不是容易出错的while循环,我使用two-argument iter
逐字节地迭代文件a。 E.g 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)
现在,创建一个方便的逐字节迭代:
>>> 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']
>>>
你会发现这留下了“结束”的第一个值。但是,清理它很简单。这是一个更加丰富的例子,在分隔符之间有几个字节“运行”:
>>> 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
要慢,但它会提高内存效率。可能有一些边缘情况需要处理,我没有想到,但我认为扩展上述方法应该是直截了当的。此外,如果存在没有相应“停止”的“开始”字节序列,target
列表将继续增长,直到文件耗尽。
最后,也许最好的方法是以可管理的块读取文件,并使用下面的逻辑处理这些块。这结合了空间和时间效率。在伪伪代码中:
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 >