ホームページ  >  記事  >  バックエンド開発  >  大きなファイルの PHP 処理のアイデア_PHP チュートリアル

大きなファイルの PHP 処理のアイデア_PHP チュートリアル

WBOY
WBOYオリジナル
2016-07-14 10:08:48894ブラウズ

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

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

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