我想用 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);
}
这个算法很简单:
为什么我要回溯3个字节?因为如果这是文件的内容。
0000 4749 524f 0000 01b0 0013
如果我不回溯3个字节,我就会读到: 0000 4749
在第一次迭代时。524f 0000
在第二个。01b0 0013
第三次,你可以看到我错过了这个序列。
问题:它慢得要命......应用程序将不得不处理大到50MB的文件,所以它将花很长时间来寻找这个序列。
在PHP中是否有一个优化的函数可以完成这项工作?有没有更快的(不是像我这样笨的)方法来做这件事?
从磁盘上进行读取总是需要很长的时间。你不能指望磁盘缓存。那是操作系统的事情。相反,做你自己的 "缓存",因为它是。读取一组很长的字节,比如可能是1M(或更多)。这样可以减少磁盘读取。然后在内存中搜索。当读取下一个1Mbytes的时候,一定要把前一组的最后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