matlab内存映射中高效的字节模式搜索



我有一个大的二进制文件(2+GB),它们按照同步模式(0xDEADBEEF)排列,后面跟着一个固定大小的数据块。示例:

0xDE AD BE EF ... 96 bytes of data
0xDE AD BE EF ... 96 bytes of data
... repeat ...

我需要定位到每个数据包开头的偏移量。理想情况下,这将只是[1:packetSize:fileSize]。然而,还有其他数据可以穿插,标题等,所以我需要在文件中搜索同步模式。

我正在使用以下代码,该代码基于Mathworks findPattern2中的Loren,但进行了一些修改以使用内存映射。

function pattLoc = findPattern(fileName, bytePattern)
%Mem Map file
m = memmapfile(fileName);
% Find candidate locations match the first element in the pattern.
pattLoc = find(m.data==bytePattern(1));
%Remove start values that are too close to the end to possibly match
len = numel(bytePattern);
endVals = pattLoc+len-1;
pattLoc(endVals>length(m.data)) = [];
% loop over elements of Sync Pattern to check possible location validity.
for pattval = 2:len
    % check viable locations in array
    locs = bytePattern(pattval) == m.data(pattLoc+pattval-1);    
    pattLoc(~locs) = []; % delete false ones from indices
end

这个效果很好。然而,我认为可能还有改进的空间。首先,我知道我的模式不能比packetSize(本例中为100)更近,但可能相距更远。似乎我应该能够以某种方式使用这些信息来加快搜索速度。第二,第5行的初始搜索使用find进行数字索引,而不是逻辑索引。这一行所用的时间几乎是将其作为逻辑行的两倍。然而,我试图只使用逻辑索引来重新编写这个函数,但失败得很惨。问题出现在循环内部,并在不使用更多查找的情况下使用逻辑跟踪嵌套索引。。。或者检查比需要的更多的数据

因此,如果能为加快这一进程提供任何帮助,我们将不胜感激。以下是一些代码,如有必要,将创建一个简单的二进制文件样例。

function genSampleFile(numPackets)
pattern = hex2dec({'DE','AD','BE','EF'});
fileName = 'testFile.bin';
fid = fopen(fileName,'w+');
for f = 1:numPackets
    fwrite(fid,[pattern; uint8(rand(96,1)*255)],'uint8');
end
fclose(fid);

搜索包含10000000个数据包的文件需要以下步骤:

>> genSampleFile(10000000); %Warning Makes 950+MB file
>> tic;pattLoc = findPattern(fileName, pattern);toc
Elapsed time is 4.608321 seconds.

您可以使用findstr立即获得提升,或者更好的是使用strfind而不是find:

pattLoc = strfind(m.data, bytePattern)

这样就不需要任何进一步的循环了。您只需要清理返回的索引数组中的一些内容。

您希望删除距离末尾不超过4个字节,但距离末尾超过100个字节的内容,因此请设置len = 100,而不是len = length(bytePattern)

要筛选出彼此之间距离小于100字节的元素,请使用索引列表上的diff

pattLoc[diff(pattLoc) < 100] = []

这应该通过更多地依赖内建来加快代码的速度,内建通常比循环效率高得多。

最新更新