Python在大fi上查找第一个(非)匹配的固定宽度字

2024-06-28 12:23:10 发布

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

我将从描述我的问题开始。我有一个二进制文件(认为它是一个相对较大的文件,例如1GiB),由8-字节的序列组成。我需要创建两个快速例程:

  1. 在该文件中搜索第一个8字节序列的索引,该序列等于0x0000000000000000

  2. 在该文件中搜索与0xFFFFFFFFFFFFFFFF不同的第一个8-字节序列的索引。

请注意,这两个例程都需要搜索对齐的序列,这意味着匹配应该从序列的开头开始。我可以更改文件格式(如下所示),但我需要它能够表示一个庞大的整数列表。此外,这个文件将从许多脚本(比如说,大约100个)同时访问(读取/更新),但是我使用fcntl.flock来避免灾难。你知道吗

到目前为止,我在每个8字节序列之前添加了一个字节分隔符(\xAA,以使搜索更容易而不发生冲突。因此,我认为第一个问题已经解决,因为我可以使用mmap.find来搜索0xAA0000000000000000的第一个出现,但是我要解决第二个问题。你知道吗

目前,为了解决第二个问题,我正在使用下面应用于mmap的regex,但我不知道是否以及如何进一步改进它(我将它分成多行,以使其更易于阅读)。你知道吗

b"\xaa(?:" \
b"[^\xff].......|" \
b".[^\xff]......|" \
b"..[^\xff].....|" \
b"...[^\xff]....|" \
b"....[^\xff]...|" \
b".....[^\xff]..|" \
b"......[^\xff].|" \
b".......[^\xff])"

为了测试这两种方法的性能,我做了下面的压力测试。它创建一个~1GiB文件,其中包含每个问题的最坏情况,即搜索需要完全解析每个序列,并尝试执行我上面提出的解决方案。你知道吗

import re
import mmap
import time

zeros = b"\xaa" + (b"\x00" * 8)
ones = b"\xaa" + (b"\xff" * 8)

regex = b"\xaa(?:" \
        b"[^\xff].......|" \
        b".[^\xff]......|" \
        b"..[^\xff].....|" \
        b"...[^\xff]....|" \
        b"....[^\xff]...|" \
        b".....[^\xff]..|" \
        b"......[^\xff].|" \
        b".......[^\xff])"

reg = re.compile(regex)

file = open("1gib", "wb")
file.write(ones * 128 * 1024 * 1024)
file.close()

file = open("1gib", "rb+")
mem = mmap.mmap(file.fileno(), 0)

start = time.time()
reg.search(mem)
print(time.time() - start) # 17.609468460083008

mem.close()
file.close()

file = open("1gib", "wb")
file.write((zeros[ : -1 ] + b"\xff") * 128 * 1024 * 1024)
file.close()

file = open("1gib", "rb+")
mem = mmap.mmap(file.fileno(), 0)

start = time.time()
mem.find(zeros)
print(time.time() - start) # 1.539649248123169

mem.close()
file.close()

从运行时可以看出find策略比regex策略快11.5倍。如何改进第二种策略,使之与第一种策略一样快?你知道吗

请注意,我对第一个策略的性能很满意,但如果您有任何改进建议,我愿意:)

非常感谢


Tags: 文件close字节time序列openfindmem