在PHP中搜索二进制文件中的字节序列?
我想使用PHP在二进制文件中查找特定的字节序列。我用十六进制表示这个序列,以避免键入过多的0和1。要查找的序列是在PHP中搜索二进制文件中的字节序列?,php,search,optimization,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) {
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);
}
算法的作用很简单:
0000 4749 524f 0000 01b0 0013
如果我不返回3个字节,我将在第一次迭代中读取0000 4749
,在第二次迭代中读取524f 0000
,在第三次迭代中读取01b0 0013
,您可以看到我错过了序列
问题:速度太慢了……应用程序必须处理50MB大小的文件,所以要找到这个序列需要很长时间
PHP中是否有一个优化的函数可以完成这项工作?有没有一种更快(不像我这样笨)的方法呢?首先,你的
$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
从磁盘读取总是需要很长时间。你不能指望磁盘缓存。这是一个操作系统的东西。取而代之的是,按原样进行自己的“缓存”。读取一长组字节,大约1M(或更多)。这减少了磁盘读取。然后在内存中搜索。在读取下一个1M字节时,请确保在前一组的最后3个字节前加上前缀。搜索每个集合,直到找到为止。读取的实际大小需要在RAM使用和磁盘读取之间保持平衡。读取的字节数很长,大约为1M(或更多)。然后在内存中搜索。当读取下一个1M字节时,一定要检查第一组的最后3个是否是指针的开始。好的,我要试试!谢谢顺便说一句,我以为文件在读取过程中缓存在memry中……你是说每次我运行函数fread时,文件都是直接从硬盘读取的吗?@AlbertoFontana这只是对相同方法的修改,只读取较大的块(我认为是4-8k),然后是“在块中查找”(vs“块精确匹配”)。要轻松处理分割的块,一个简单的方法是同时向后搜索,这样块实际上会重叠几个字节(如果搜索频率相对较低,这种近距离搜索就足够了)。正是减少了系统调用的数量才是最大的性能差异。另外,通过将$mysequence转换为字节序列,而不是总是转换读取的数据,还可以减少一点工作。缓存是由操作系统来完成的。对大的读取进行自己的缓存。在读取下一组字节后,在前一组字节的最后3个字节前加前缀并开始搜索。我不明白你说的是:“搜索时你的$seq没有变化,所以你可以调用bin2hex()一次。”。当然$seq会改变,因为我在每个循环中读到一个新的序列…我错了吗?我的错。您可以调用
hex2bin($mysequence)
并与$seq进行比较。每次都不调用bin2hex
。