ホームページ  >  記事  >  バックエンド開発  >  PHP は file 関数と fseek 関数を使用して大きなファイルを読み取る効率分析

PHP は file 関数と fseek 関数を使用して大きなファイルを読み取る効率分析

高洛峰
高洛峰オリジナル
2016-11-04 16:01:441253ブラウズ

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

1. file 関数を直接使用して操作します

file 関数はすべてのコンテンツを一度にメモリに読み取るため、PHP は、不適切に作成されたプログラムがメモリを占有しすぎてシステム メモリが不足し、サーバーがクラッシュすることを防ぎます。ダウンタイムのため、デフォルトでは最大メモリ使用量は 16M に制限されます。この値は php.ini のmemory_limit = 16M で設定されます。この値が -1 に設定されている場合、メモリ使用量は制限されません。

以下は、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 (s)かかります

方法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) かかります

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