【问题标题】:stristr and speedstristr 和 速度
【发布时间】:2011-04-09 13:06:08
【问题描述】:

我有两个文件,文件 a 大约 5mb,文件 b 大约 66mb。我需要找出文件a,文件b内部是否有任何行,如果有,将它们写入文件c。

这是我目前的处理方式:

ini_set("memory_limit","1000M");
set_time_limit(0);
$small_list=file("a.csv");
$big_list=file_get_contents("b.csv");
$new_list="c.csv";
$fh = fopen($new_list, 'a');
foreach($small_list as $one_line)
{
 if(stristr($big_list, $one_line) != FALSE) 
    {
    fwrite($fh, $one_line);
    echo "record found: " . $one_line ."<br>";
    }   
}

问题是它已经(成功地)运行了一个多小时,并且它可能有 3,000 行变成了较小文件中的 160,000 行。有什么想法吗?

【问题讨论】:

    标签: php string performance


    【解决方案1】:

    先尝试对文件进行排序(尤其是大文件)。然后您只需要检查 b 中每一行的前几个字符,并在超过该前缀时停止(转到 a 中的下一行)。然后,您甚至可以对文件中每个字符的第一个位置进行索引(a 从第 0 行开始,b 从第 1337 行开始,c 从第 13986 行开始,依此类推)。

    【讨论】:

      【解决方案2】:

      尝试在循环中使用ob_flush()flush()

      foreach($small_list as $one_line)
      {
       if(stristr($big_list, $one_line) != FALSE) 
          {
          fwrite($fh, $one_line);
          echo "record found: " . $one_line ."<br>";
          }  
             @ob_flush();
              @flush();
              @ob_end_flush(); 
      }
      

      【讨论】:

      • 这将如何加快搜索速度?
      【解决方案3】:

      构建以哈希为索引的数组:

      逐行读入文件a.csv并存入a_hash[md5($line)] = array($offset, $length) 逐行读入文件b.csv并存入b_hash[md5($line)] = true

      通过使用哈希作为索引,您将自动不会有重复的条目。

      然后,对于在 a_hash 和 b_hash 中都有索引的每个散列,读取文件内容(使用存储在 a_hash 中的偏移量和长度)以提取实际的行文本。如果您对哈希冲突有疑虑,请同时存储 b_hash 的偏移量/长度,并使用 stristr 进行验证。

      这将运行得更快,并且使用的内存要少得多。

      如果您想进一步减少内存需求并且不介意检查重复项,那么:

      逐行读取文件a.csv并存储在a_hash[md5($line)] = false
      逐行读取文件b.csv,对该行进行哈希处理并检查a_hash中是否存在。
      如果a_hash[md5($line)] == false 写入c.csv 并设置a_hash[md5($line)] = true

      第二个建议的一些示例代码:

      $a_file = fopen('a.csv','r');
      $b_file = fopen('b.csv','r');
      $c_file = fopen('c.csv','w+');
      
      if(!$a_file || !$b_file || !$c_file) {
          echo "Broken!<br>";
          exit;
      }
      
      $a_hash = array();
      
      while(!feof($a_file)) {
          $a_hash[md5(fgets($a_file))] = false;
      }
      fclose($a_file);
      
      while(!feof($b_file)) {
          $line = fgets($b_file);
          $hash = md5($line);
          if(isset($a_hash[$hash]) && !$a_hash[$hash]) {
              echo 'record found: ' . $line . '<br>';
              fwrite($c_file, $line);
              $a_hash[$hash] = true;
          }
      }
      
      fclose($b_file);
      fclose($c_file);
      

      【讨论】:

      • 这有点超出我的想象,你知道我可以学习如何正确执行此操作的好资源吗?
      • 为你添加了一个例子。似乎工作正常,但我还没有完全进行广泛的调试。应该足以让您看到正在发生的事情,并且与您的原始版本相比,它将在很小的空间内运行。
      • 哇,它成功地在大约 45 秒内完成了整个 65mb 文件...非常感谢,你为我节省了一个非常非常深的夜晚。也是我最喜欢的新词。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-30
      • 2012-12-14
      • 1970-01-01
      • 2010-11-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多