Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/search/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在PHP中搜索二进制文件中的字节序列?_Php_Search_Optimization - Fatal编程技术网

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

在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) {

我想使用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);
}
算法的作用很简单:

  • 读取4个字节
  • 检查它们是否等于序列
  • 如果它们相等->找到!停止执行
  • 如果它们不相等,并且我不在文件末尾,则返回文件中的3个字节,并重复步骤1
  • 为什么我要返回3个字节?因为如果这是文件的内容:

    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