PHP での大きなファイルの読み書きに関する問題
通常の学習や開発では、大量のデータ入力の読み書きに触れることがほとんどないため、そのような必要性が突然生じた場合でも、
は、 file_get_contents、fread、その他のファイルを読み取るメソッドなど、より高速なメソッドに従うことができますが、読み取られたファイルが
では、大きなファイルの読み書き時に が検索されるという問題が発生します。インターネットでいくつかの情報を見つけましたが、いくつかの例はうまくいきませんでした。私のニーズを満たしているので、オンラインですでに持っているものと組み合わせました。たとえば、別の結論のブログを書きましょう 。
それでは、具体的には何が起こるのでしょうか?これは、PHP の基礎となる実装である number、file_get_contents について話しましょう。 fread
まず、PHP の ファイル読み取り関数、 file_get_contents について説明します。 fread、これら 2 つの関数は実際には同じ原理で、システムのメモリにコンテンツを読み取ります。ただし、ファイルの内容を文字列として読み込むだけの場合は、file_get_contents() を使用してください。そのパフォーマンスは fread() よりもはるかに優れています。
それほど大きくないファイルを読み取る場合はまだ問題ありませんが、大きなファイルを読み取る場合は (たとえば、2GB のログ)、マシンのメモリが 4G しかない場合、
ファイル全体を読み取って文字列に保存すると、システムの動作や他のプロセスの動作を維持するために に使用されるメモリの一部がまだ残っているため、システムのメモリが爆発してフリーズする可能性があります。このような場合があるため、一度に大量のコンテンツを読み取らないようにするには他のメソッドが必要であり、この
メソッドを使用して大きなファイルの読み取りを実現します。 PHP ファイルの読み取り:
以下は、オンラインで大きなファイルを読み取る例です。上記のメモリが爆発する現象。 。
_______________________________ 無敵の分かれ目_______________________________________________
要件は次のとおりです。
約 500 万行の約 1G のログ ファイルがあり、php を使用して最後の数行の内容を返します。
実装方法:1. ファイル関数を直接使用して操作します
注: ファイル関数はすべてのコンテンツを一度にメモリに読み込むため、 PHP は、一部の不適切に作成されたプログラムがメモリを占有しすぎてシステム メモリが不足し、サーバーがクラッシュすることを防ぐために、デフォルトで最大メモリ使用量が 16M に制限されています。これは、php.ini 設定でのmemory_limit = 16M によって行われます。 、この値が -1 に設定されている場合、メモリ使用量は制限されません。
次は、file を使用してこのファイルの最後の行を抽出するコードです。
コード全体の実行には時間がかかります。 116.9613 (s ).
上記の例は最後の数行を読み込む例ですが、ファイルの内容をトラバースするので読み込むのと同じですファイル全体、ただし >
コンテンツの最後の数行を読みたい場合は、fseek を直接使用してコンテンツの一部を位置決めして読み取ることもできます。
大きなファイルの読み取りと書き込みの方法について説明します。
大きなファイルの読み込み:
読み込み部分が必要なため、ファイルは特に大きくないので、file_get_contents または fread 独自のセグメンテーション パラメーターを使用して、読み取り用のブロックに分割できます (IO のピーク サイズを減らすためにここにスリープ関数を追加する必要があるように感じますが、それが正しいかどうかはわかりません。ダニエルが指摘してくれたといいのですが) 、fgets を使用して while ループで 1 行ずつ読み取るという方法もあります。これは、fgetss がファイル ポインターを介して 1 行ずつ読み取るためです。比較的高いです。
以下に、fgets を通じて大きなファイルを読み取り、ファイルの内容をエンコードする例を示します (UTF-8 -> GBK)。は次のとおりです:
$file = fopen($old_file_path,"r"); $result = fopen($temporary_file_path,"a"); $re_sign = 0; while(!feof($file)) { $content = fgets($file); $encode = mb_detect_encoding($content, array('ASCII','UTF-8','GB2312','GBK','BIG5')); if ($encode == 'UTF-8') { $str = iconv($encode,"GBK//IGNORE", $content); $encode = mb_detect_encoding($content, array('ASCII','UTF-8','GB2312','GBK','BIG5')); fwrite($result, $str); $re_sign = 1; } else { fwrite($result, $content); } } fclose($file); fclose($result); if($re_sign == 1){ rename($old_file_path, $old_file_path . '.bak' ); rename($temporary_file_path, $old_file_path); } else { unlink($temporary_file_path); }
大きなファイルの書き込み:
大きなファイルの書き込みは、大きなファイルの読み取りよりも発生する可能性が高くなります。一度に多くのファイルが書き込まれる場合、
が原因でハードディスクがスタックするだけなので、コストはそれほど高くありません。効率の観点 1 回限りの直接書き込みが最も時間がかかり効率的であるため、大きなファイルを書き込む場合は、一度読み取ってからファイルに直接書き込むことをお勧めします。