我想使用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);
}
算法的作用很简单:
为什么我要回3个字节?因为如果这是文件的内容:
0000 4749 524f 0000 01b0 0013
如果我没有返回3字节,我将在第一次迭代时读取0000 4749
,在第二次迭代时读取524f 0000
,在第三次迭代时读取01b0 0013
,你可以看到我错过了顺序。
问题:它像地狱一样缓慢......应用程序必须使用最大50MB的文件,因此需要永远找到这个序列。
PHP中是否有一个优化的功能可以完成这项工作?这样做有更快(不像我的傻)的方法吗?
答案 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使用和磁盘读取之间取得平衡。