81

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

ここには、ファイルから最後の 1 行を取得する方法に関する質問があり (ただし、N行が必要です)、さまざまな解決策が示されています。どちらが優れていて、どちらが優れているかはわかりません。

4

7 に答える 7

281

メソッドの概要

インターネットで検索すると、さまざまな解決策が見つかりました。それらを次の 3 つのアプローチにグループ化できます。

  • file()PHP 関数を使用する単純なもの。
  • tailシステム上でコマンドを実行する不正行為。
  • . _ fseek()_

私は最終的に 5つの解決を選択 (または作成) しまし

  1. 組み込みの配列関数を使用した、最も簡潔な単純なソリューション。
  2. commandに基づく唯一tailの可能な解決策ですが、少し大きな問題があります: がtail利用できない場合、つまり非 Unix (Windows) またはシステム機能を許可しない制限された環境では実行されません。
  3. 改行文字を検索 (およびカウント) するファイルの終わりから1 バイトを読み取るソリューションは、こちらにあります。
  4. 大きなファイル用に最適化され たマルチバイト バッファリングソリューションは、こちらにあります
  5. バッファ長が動的で、取得する行数に応じて決定される解決策 #4のわずかに変更されたバージョン。

すべてのソリューションが機能します。任意のファイルから期待される結果を返すという意味で、任意の行数を要求します (解決策 #1 を除き、大きなファイルの場合に PHP のメモリ制限を破ることができ、何も返されません)。しかし、どちらが良いですか?

性能試験

質問に答えるために、テストを実行します。それがこれらのことが行われる方法ですよね?

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

PHP コマンド ライン インタープリターを使用して、ローカルの開発マシン (Xubuntu 12.04、PHP 5.3.10、2.70 GHz デュアル コア CPU、2 GB RAM) でスクリプトを実行します。結果は次のとおりです。

サンプルの 100 KB ログ ファイルの実行時間

解決策 #1 と #2 は悪いもののようです。解決策 3 は、数行を読む必要がある場合にのみ有効です。ソリューション #4 と #5 が最適なようです。 動的バッファー サイズがアルゴリズムを最適化する方法に注意してください。バッファーが削減されるため、数行の実行時間は少し短くなります。

もっと大きなファイルで試してみましょう。10 MBのログ ファイルを読み取る必要がある場合はどうなるでしょうか。

サンプルの 10 MB ログ ファイルの実行時間

解決策 #1 は、はるかに悪いものです。実際、10 MB のファイル全体をメモリにロードすることは、良い考えではありません。1MB と 100MB のファイルでもテストを実行しましたが、実質的に同じ状況です。

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

サンプルの 10 KB ログ ファイルの実行時間

解決策 #1 が今のところ最適です。10 KB をメモリにロードすることは、PHP にとって大したことではありません。また、#4 と #5 のパフォーマンスも良好です。ただし、これはエッジ ケースです。10 KB のログは、150/200 行のようなものを意味します...

すべてのテスト ファイル、ソース、および結果を ここからダウンロードできます。

最終的な考え

解決策 5は、一般的なユース ケースに強く推奨されます。すべてのファイル サイズでうまく機能し、数行を読み取るときに特に優れたパフォーマンスを発揮します。

10 KB を超えるファイルを読み取る必要がある場合は、解決策 1を避けてください。

解決策#2#3 は、私が実行する各テストに最適なものではありません: #2 は 2 ミリ秒未満で実行されることはありません。 )。

于 2013-02-22T13:59:03.117 に答える