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

时间:2016-04-18 15:17:52

标签: matlab

我有大型二进制文件(2+ GB),这些文件以同步模式(0xDEADBEEF)排列,后跟固定大小的数据块。 例如:

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

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

我正在使用以下基于Loren from Mathworks findPattern2的代码,但稍微修改了一下以使用内存映射。

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.

1 个答案:

答案 0 :(得分:1)

您可以使用findstr或更好strfind代替find立即获得提升:

pattLoc = strfind(m.data, bytePattern)

这消除了进一步循环的需要。你只需要在返回的索引数组中清理一些东西。

你想要删除距离最近100个字节的东西,最后不要超过4个字节,所以设置len = 100,而不是len = length(bytePattern)

要过滤掉彼此距离小于100个字节的元素,请在索引列表中使用diff

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

这可以通过更多地依赖于内置来加速你的代码,内置函数通常比循环更有效。