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

时间:2015-09-09 18:44:17

标签: php search optimization

我想使用PHP在二进制文件中找到特定的字节序列。我用十六进制表示这个序列,以避免输入太多的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.
  5. 为什么我要回3个字节​​?因为如果这是文件的内容:

    0000 4749 524f 0000 01b0 0013
    

    如果我没有返回3字节,我将在第一次迭代时读取0000 4749,在第二次迭代时读取524f 0000,在第三次迭代时读取01b0 0013,你可以看到我错过了顺序。

    问题:它像地狱一样缓慢......应用程序必须使用最大50MB的文件,因此需要永远找到这个序列。

    PHP中是否有一个优化的功能可以完成这项工作?这样做有更快(不像我的傻)的方法吗?

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

从磁盘读取操作总是需要很长时间。您不能指望磁盘缓存。这是操作系统的事情。相反,做你自己的“缓存”,就像它一样。读入一长串字节,类似于1M(或更多)。这减少了磁盘读取。然后在内存中搜索。读取下一个1M字节时,请务必在前面添加前一个字节的最后3个字节。搜索每一组直到找到。读取的实际大小需要在RAM使用和磁盘读取之间取得平衡。