ホームページ  >  記事  >  バックエンド開発  >  PHP が大きなファイルを効率的に読み取る方法の例の比較

PHP が大きなファイルを効率的に読み取る方法の例の比較

*文
*文オリジナル
2017-12-29 18:59:442165ブラウズ

大きなファイルの読み込みは常に頭の痛い問題です。PHP を使用して小さなファイルを開発し、読み込む場合は、さまざまな関数を直接使用してそれを実現できますが、大きな記事になると、一般的に使用されている方法では不可能であることがわかります。では、PHP での大きなファイルの読み取りの問題の解決策を見てみましょう。これが皆さんのお役に立てれば幸いです。

PHP では、ファイルを読み取るときに、file や file_get_contents などの関数を使用するのが最も簡単な方法で、数行の簡単なコードで必要な関数を美しく完成させることができます。ただし、操作するファイルが比較的大きなファイルの場合、これらの機能では不十分な場合があります。ここでは、大きなファイルを読み込むときによく使用される操作方法について説明します。

要件:
約 500 万行を含む 800M のログ ファイルがあり、PHP を使用して最後の数行の内容を返します。

実装方法:

1. ファイル関数を直接使用して操作します
ファイル関数はすべての内容を一度にメモリに読み取るため、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 (s) かかります。
私のマシンには 2G のメモリがあり、F5 を押して実行すると、システムが灰色になり、ほぼ 20 分後に回復します。このような大きなファイルをメモリに直接読み込むと、非常に深刻な結果になることがわかります。いいえ、必要ありません。memory_limit を高く設定しすぎることはできません。そうでない場合は、コンピュータ室に電話してマシンをリセットするように依頼するしかありません。

2. Linux tail コマンドを直接呼び出して、最後の数行を表示します
Linux コマンド ラインで、tail -n 10 access.log を直接使用して、ログ ファイルの最後の数行を簡単に表示できます。 PHP で tail コマンドを呼び出すには、次のように PHP コードを実行します:

<?php
  $file = &#39;access.log&#39;;
  $file = escapeshellarg($file); // 对命令行参数进行安全转义
  $line = `tail -n 1 $file`;
  echo $line;
?>

コード全体の実行には 0.0034 (s)

3 かかります。PHP の fseek を直接使用してファイル操作を実行します。この方法は最も一般的な方法です。ファイルのすべての内容を必要としない 内容を読み取る代わりに、ポインタを介して直接操作するため、効率が非常に高くなります。 fseek を使用してファイルを操作する場合、さまざまな方法があり、効率は若干異なる場合があります。一般的に使用される 2 つの方法は次のとおりです:

方法 1

最初に fseek でファイルの最後の EOF を検索し、次に先頭の 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--;
 }
 $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)
 {
 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) かかります

方法 4、PHP の stream_get_line 関数は読み取りが速く、500,000 データを含む大きなファイルを読み取るのに約 20 秒かかります。サンプルコードは以下の通りです

$fp = fopen(&#39;./iis.log&#39;, &#39;r&#39;); //文件 
while (!feof($fp)) { 
 //for($j=1;$j<=1000;$j++) {     //读取下面的1000行并存储到数组中 
 $logarray[] = stream_get_line($fp, 65535, "\n"); 
    // break;
 // } 
 
 }

関連推奨事項:

phpファイル読み込みシリーズメソッドの詳細説明

PHPファイル読み込みfread、fgets、fgetc、file_get_contentsとファイル関数の使用例コード

PHP ファイルロックとプロセスロックの簡単な紹介

以上がPHP が大きなファイルを効率的に読み取る方法の例の比較の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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