1. ホーム
  2. php

[解決済み] PHP を使ってファイルの最終行を読み取るための最良の方法は何ですか?

2023-07-19 05:45:43

質問

私のPHPアプリケーションでは、次のことが必要です。 の末尾から始まる複数の行を読み取る必要があります。 多くのファイル (主にログ)。最後の1行だけが必要なこともあれば、数十行、数百行が必要なこともあります。 数十または数百を必要とします。基本的に、私はUnixの tail コマンドのように柔軟なものが欲しいのです。

ここでは、ファイルから最後の1行を取得する方法についての質問があります(しかし 必要なのは N 行が必要です)、そして異なった解決策が与えられました。どれがベストで、どれがより良いパフォーマンスなのか、よくわかりません。 がベストで、どちらがより良いパフォーマンスなのかわかりません。

どのように解決するのですか?

メソッドの概要

インターネットで検索していると、さまざまなソリューションに出会います。私はそれらを次の 3 つのアプローチにまとめることができます。 3つのアプローチに分類できます。

  • 素朴 を使用するもの file() PHPの関数です。
  • 不正行為 走っているもの tail コマンドを実行するもの。
  • 強大な を使って、開いたファイルの中を嬉々として飛び回るもの。 fseek() .

結局、5つの解決策を選んだ(書いた)のですが、そのうちの1つは 素朴な というもの、そして インチキ 一つ と3つの 強大 のものです。

  1. 最も簡潔な 素朴な 解決策 , 組み込みの配列関数を使用して。
  2. に基づく唯一の可能な解決策は tail コマンド がありますが、これには は少し大きな問題があります。 tail が利用できない場合、つまり 非Unix(Windows)やシステム関数を許可しない制限された環境など、が利用できない場合は実行されません。 関数を許可しない制限された環境などです。
  3. での解決策は シングルバイト を検索して、ファイルの終わりから読み込まれます。 を検索し、改行文字をカウントすることで はここで .
  4. マルチバイトバッファード のソリューションは、大きなファイルのために最適化され、見つかった ここで .
  5. 若干の 解決策4の修正版 この場合、バッファの長さは であり、取得する行数に応じて決定されます。

すべてのソリューション 作業 . どのようなファイルでも、どのような行数でも、期待通りの結果を返すという意味では どのようなファイルでも、どのような行数でも、期待通りの結果を返すという意味で (ただし、#1 の解決策は、ファイルが大きい場合に PHP のメモリ制限にひっかかる可能性があり は、大きなファイルの場合に PHP のメモリ制限を破って何も返さない可能性があります)。しかし、どれが が良いのでしょうか?

パフォーマンステスト

質問に答えるために、私はテストを実行します。こういうのはそういうものでしょう?

サンプルを用意しました。 100KBのファイル で見つけた異なるファイルを結合して 私の /var/log ディレクトリにある異なるファイルを結合しています。それから、5つの解決策のそれぞれを使用するPHPスクリプトを書きました。 を取得する PHP スクリプトを作成しました。 1, 2, .., 10, 20, ... 100, 200, ..., 1000 行 をファイルの末尾から順に実行します。それぞれのテストは10回繰り返されます(これは のようなものです。 5 × 28 × 10 = 1400 のように)、測定します。 平均経過時間 時間 をマイクロ秒単位で測定します。

私のローカルの開発マシン (Xubuntu 12.04, PHP 5.3.10, 2.70 GHz dual core CPU, 2 GB RAM) で PHP コマンドライン インタープリターを使用してスクリプトを実行しました。 インタプリタを使って実行しました。以下はその結果です。

解決策#1と#2は、より悪いもののようです。3は、数行を読む必要がある場合のみ有効です。 数行を読む必要があるときだけです。 解決策#4と#5は最も良いもののように思われる。 動的バッファサイズによってアルゴリズムがどのように最適化されるかに注目。 実行時間は、バッファが減少しているため、数行で少し小さくなります。

より大きなファイルで試してみましょう。もし私たちが 10 MB のログファイルを読まなければならないとしたらどうでしょう?

さて、解決策その 1 は圧倒的に悪いものです:実際、10 MB のファイル全体をメモリにロードすることは をメモリに読み込むことは、良いアイデアではありません。私は 1MB と 100MB のファイルでもテストを実行しました。 実質的に同じ状況です。

小さなログファイルの場合は?のグラフです。 10 KB ファイルのグラフです。

解決策その1は、今一番良い方法です! 10KBをメモリにロードすることは、PHPにとって大きな問題ではありません。 PHPにとって大きな問題ではありません。また、#4 と#5 も良いパフォーマンスです。しかし、これはエッジケースです:10KBのログは は、150/200 行を意味する...

<ブロッククオート

私のテストファイル、ソース、結果をすべてダウンロードすることができます。 ここで .

最終的な感想

ソリューション#5 は、一般的な使用例として強く推奨されます。 どのようなファイル サイズでもうまく機能し、数行を読み取るときに特に優れたパフォーマンスを発揮します。

避けるべきは 解決策その1 もし は、10KB以上のファイルを読み込む必要があります。

解決方法 #2 そして #3 は、私が実行する各テストで最適なものではありません。#2 は 2ms 以下で実行されることはありません。 2は2ms以下で実行されることはなく、#3は質問した行数に大きく影響されます。 の行数に大きく影響されます(1、2行でかなりうまくいきます)。