ホームページ  >  記事  >  バックエンド開発  >  PHPのfile関数とfseek関数による大容量ファイルの読み込み効率の比較分析

PHPのfile関数とfseek関数による大容量ファイルの読み込み効率の比較分析

高洛峰
高洛峰オリジナル
2016-12-26 14:12:541549ブラウズ

PHP では、大きなファイルを読み取るために file 関数と fseek 関数を使用できますが、この 2 つの関数には効率に違いがある可能性があります。この記事では、php file 関数と fseek 関数の間で大きなファイルの読み取り効率を比較分析したものを紹介します。困っている友達は参考にしてください。

1. ファイル関数を直接使用して操作します

ファイル関数はすべてのコンテンツを一度にメモリに読み取るため、PHP は、一部の不適切に作成されたプログラムがメモリを占有しすぎてシステム メモリが不足するのを防ぐために、サーバーのメモリ不足が発生するため、デフォルトでは最大メモリ使用量が 16M に制限されます。この値が -1 に設定されている場合、これはメモリ使用量を 16M に設定します。限定されるものではありません。

以下は、 file を使用してこのファイルの最後の行を抽出するコードです:

<?php
  ini_set(&#39;memory_limit&#39;, &#39;-1&#39;);
  $file = &#39;access.log&#39;;
  $data = file($file);
  $line = $data[count($data) - 1];
  echo $line;
  ?>

コード全体の実行には 116.9613 (秒) かかります。

私のマシンには 2G のメモリがあり、F5 キーを押して実行すると、システムが直接グレーになり、約 20 分後に回復します。このような大きなファイルをメモリに直接読み込むと重大な結果が生じることがわかります。ここでは説明しません。最後の手段として、memory_limit を高く設定しすぎると、コンピュータ室に電話してマシンをリセットする必要があります。

2. PHP の fseek を直接使用してファイル操作を実行する

この方法は、ファイルのすべての内容をコンテンツに読み取る必要がなく、ポインターを介して直接操作するため、非常に効率的です。 。 fseek を使用してファイルを操作する場合、さまざまな方法があり、効率は若干異なる場合があります。一般的に使用される方法は次の 2 つです:

方法 1

まず、fseek を通じてファイルの最後の EOF を見つけます。最後の行の位置を確認し、この行のデータを取得し、次の行の開始位置を見つけて、この行の位置を取得するというように、$num 行が見つかるまで続きます。

実装コードは次のとおりです

<?php
  $fp = fopen($file, "r");
  $line = 10;
  $pos = -2;
  $t = " ";
  $data = "";
  while ($line > 0)
  {
    while ($t != "\n")
    {
      fseek($fp, $pos, SEEK_END);
      $t = fgetc($fp);
      $pos--;
    }// http://www.manongjc.com
    $t = " ";
    $data .= fgets($fp);
    $line--;
  }
  fclose($fp);
  echo $data
  ?>

コード全体の実行には0.0095(秒)かかります

方法2

は引き続きfseekを使用してファイルの終わりから読み取りますが、今回はファイルの終わりから読み取りません代わりに、データが読み取られるたびに、読み取られたデータが buf に配置され、改行文字の数 (n) を使用して最後の $num 行かどうかが判断されます。のデータが読み取られました。

実装コードは以下の通りです

<?php
  $fp = fopen($file, "r");
  $num = 10;
  $chunk = 4096;
  $fs = sprintf("%u", filesize($file));
  $max = (intval($fs) == PHP_INT_MAX) ? PHP_INT_MAX : filesize($file);
  for ($len = 0; $len < $max; $len += $chunk)
  {
    $seekSize = ($max - $len > $chunk) ? $chunk : $max - $len;
    fseek($fp, ($len + $seekSize) * -1, SEEK_END);
    $readData = fread($fp, $seekSize) . $readData;
    if (substr_count($readData, "\n") >= $num + 1)
    {
      // 作者:码农教程  http://www.manongjc.com
      preg_match("!(.*?\n){" . ($num) . "}$!", $readData, $match);
      $data = $match[0];
      break;
    }
  }
  fclose($fp);
  echo $data;
  ?>

コード全体の実行には0.0009(秒)かかります。

方法 3

<?php
  function tail($fp, $n, $base = 5)
  {
    assert($n > 0);
    $pos = $n + 1;
    $lines = array();
    while (count($lines) <= $n)
    {
      try
      {
        fseek($fp, -$pos, SEEK_END);
      }
      catch (Exception $e)
      {
        fseek(0);
        break;
      }
      $pos *= $base;
      while (!feof($fp))
      {
        array_unshift($lines, fgets($fp));
      }
    }
   
    return array_slice($lines, 0, $n);
  }
   
  var_dump(tail(fopen("access.log", "r+"), 10));
  ?>

コード全体の実行には 0.0003(s) かかります

以上がこの記事の全内容であり、皆様の学習に役立つことを願っております。中国語のウェブサイト。

PHP の file 関数と fseek 関数を使用した大きなファイルの読み取り効率の比較分析に関するその他の関連記事については、PHP 中国語 Web サイトに注目してください。


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。