PHP でファイルを読み取るとき、最も速い方法は、file や file_get_contents などの関数を使用することです。わずか数行のコードで、非常に必要な関数を完成させることができます。美しく。ただし、操作するファイルが比較的大きなファイルの場合、これらの機能では不十分な場合があります。ここでは、大きなファイルを読み取るための一般的な操作方法について説明します。
需要
約 500 万行を含む 8 億のログ ファイルがあります。PHP を使用して最後の数行の内容を返します。
実施方法
1. ファイル機能を直接使用して操作します
ファイル関数はすべての内容を一度にメモリに読み取るため、また、不適切に作成されたプログラムがメモリを大量に消費し、システム メモリ不足を引き起こしてサーバーがクラッシュすることを防ぐために、PHP にはデフォルトで最大制限が設定されています。 php.ini のmemory_limit = 16M で設定されたメモリ 16M を使用します。この値が -1 に設定されている場合、メモリ使用量は制限されません。
以下は、 file を使用してこのファイルの最後の行を抽出するコードです:
コードは次のとおりです | |
ini_set('memory_limit', '-1'); $file = 'access.log'; $data = ファイル($file); $line = $data[count($data) - 1]; エコー $line; ?> |
コード全体の実行には 116.9613 (秒) かかります。
私のマシンには 2G のメモリがあり、F5 キーを押して実行すると、システムが灰色になり、ほぼ 20 分後にのみ回復します。このような大きなファイルをメモリに直接読み込むと重大な結果が生じることがわかります。いいえ、memory_limit をあまり高く調整することはできません。そうでない場合は、コンピューター室に電話してマシンをリセットするように依頼するしかありません。
2. Linux tail コマンドを直接呼び出して、最後の数行を表示します
Linux コマンドラインでは、tail -n 10 access.log を直接使用して、ログ ファイルの最後の数行を簡単に表示できます。PHP を直接使用して、tail コマンドを呼び出すことができます。
実行 PHP コードは次のとおりです。コードは次のとおりです | |
$file = 'access.log'; $file =scapeshellarg($file); // コマンドライン引数を安全にエスケープします $line = `tail -n 1 $file`; エコー $line; ?> |
コード全体の実行には 0.0034 (秒) かかります
3. PHP の fseek を直接使用してファイル操作を実行します
この方法は最も一般的な方法であり、ファイルの内容をすべて読み取る必要はなく、ポインターを介して直接操作するため、効率が非常に高くなります。 fseek を使用してファイルを操作する場合、さまざまな方法があり、効率が若干異なる場合があります。一般的に使用される方法は次の 2 つです。
方法1最初に fseek を通じてファイルの最後の EOF を見つけ、次に最後の行の開始位置を見つけ、この行のデータを取得し、次に次の行の開始位置を見つけて、この行の位置を取得する、というように続きます。 $ num 行が見つかるまで続けます。
#実装コードは以下の通りです
コードは次のとおりです | |
$fp = fopen($file, "r"); $num = 10; $チャンク = 4096; $fs = sprintf("%u", ファイルサイズ($file)); $max = (intval($fs) == PHP_INT_MAX) : ファイルサイズ($file); for ($len = 0; $len { $seekSize = ($max - $len > $chunk) : $max - $len; fseek($fp, ($len + $seekSize) * -1, SEEK_END); $readData = fread($fp, $seekSize) . if (substr_count($readData, "\n") >= $num + 1) { preg_match("!(.*?\n){" . ($num) . "}$!", $readData, $match); $data = $match[0]; 休憩; } } fclose($fp); $data をエコー; ?> |
方法 3
関数 tail($fp, $n, $base = 5) { アサート($n > 0); $pos = $n + 1; $lines = array(); while (count($lines) { 試してみてください { fseek($fp, -$pos, SEEK_END); } catch (例外 $e) { fseek(0); 休憩 } $pos *= $base; その間 (!feof($fp)) { array_unshift($lines, fgets($fp)); } } return array_slice($lines, 0, $n);
}
?> |