在 PHP 中搜索二进制文件中的字节序列?

问题描述 投票:5回答:2

我想用 PHP 在一个二进制文件中查找一个特定的字节序列,我用十六进制表示这个序列,以避免输入太多的 0 和 1。为了避免输入过多的0和1,我用十六进制表示这个序列。要查找的序列是 0x4749524f. 这是我目前想到的工作方案。

$mysequence = "4749524f";
$f = fopen($filename, "r") or die("Unable to open file!");
while(!feof($f)) {
    $seq = fread($f, 4);
    if(bin2hex($seq) == $mysequence) {
        echo "found!";
        break;
    }
    else if(!feof($f)) fseek($f, -3, SEEK_CUR);
}

这个算法很简单:

  1. 读取4个字节
  2. 检查它们是否等于序列
  3. 如果它们相等->发现! 停止执行。
  4. 如果它们不相等,而且我还没有到文件的最后,就回到文件中的3个字节,并重复步骤1。

为什么我要回溯3个字节?因为如果这是文件的内容。

0000 4749 524f 0000 01b0 0013

如果我不回溯3个字节,我就会读到: 0000 4749 在第一次迭代时。524f 0000 在第二个。01b0 0013 第三次,你可以看到我错过了这个序列。

问题:它慢得要命......应用程序将不得不处理大到50MB的文件,所以它将花很长时间来寻找这个序列。

在PHP中是否有一个优化的函数可以完成这项工作?有没有更快的(不是像我这样笨的)方法来做这件事?

php search optimization
2个回答
1
投票

从磁盘上进行读取总是需要很长的时间。你不能指望磁盘缓存。那是操作系统的事情。相反,做你自己的 "缓存",因为它是。读取一组很长的字节,比如可能是1M(或更多)。这样可以减少磁盘读取。然后在内存中搜索。当读取下一个1Mbytes的时候,一定要把前一组的最后3个字节前置。搜索每一组,直到找到为止。你的实际读取大小需要在内存使用量和磁盘读取量之间取得平衡。


3
投票

首先你的 $mysequence 在搜索的时候没有变化,所以你可以调用 hex2bin($mysequence) 比一比 $seq 直接进行。

至于真正做得更快,你可以尝试在大缓冲区中读取和搜索字符串。大缓冲区=>搜索速度更快,但需要更多的内存。快速代码稿,这个应该是怎样的。

$mysequence = "4749524f";
$searchBytes = hex2bin($mysequence);
$crossing = 1 - length($searchBytes); // - (length - 1); see below
$buf = ''; $buflen = 10000;
$f = fopen($filename, "r") or die("Unable to open file!");
while(!feof($f)) 
{
    $seq .= fread($f, $buflen);
    if(strpos($seq, $searchBytes) === false) // strict comparation here. zero can be returned!
    {
        // keep last n-1 bytes, because they can be beginning of required sequence
        $seq = substr($seq, $crossing);
    }
    else
    {
        echo "found!";
        break;
    }
}
unset($seq); // no need to keep this in memory any more
© www.soinside.com 2019 - 2024. All rights reserved.