PHPで複数ファイルを一行ずつ処理する。

この記事では、コマンドライン引数で
複数ファイル指定して、一行ずつ処理する為の実装を
コピペして利用できるようにサンプルとして、ここに載せておきます。

指定ファイルを一行ずつ処理する

コマンドライン引数で、
指定したファイルを一行ずつ処理するようなスクリプト
php readline.php a.txt

realine.php というのは、
指定されたファイルを、
単純に一行ずつechoするスクリプトとします。

複数の指定ファイルを一行ずつ処理する

更に、コマンドライン引数に、
単一ファイルだけでなく、
複数指定したい場合もありますよね。

例えば、
php readline.php a.txt b.txt

または、ワイルドカードを利用して
php readline.php *.txt

こんな感じに利用しても、
同様に一行ずつ処理できると便利です。

実装サンプル

コマンドライン引数で、複数ファイルを指定しても、
全ファイルを、一行ずつ処理するような、
実装サンプルを記載していきましょう。

readline.php

<?php

// 引数に指定されたファイルを一つずつ処理
for ($i = 1; $i < $argc; $i++) {
    $fileName = $argv[$i];

    // ファイルを開く
    $fp = @fopen($fileName, "r");
    if (!$fp) {
        fputs(STDERR, "Failed to open file: $fileName\n");
        continue;
    }

    // 一行ずつ処理
    while (false !== ($line = fgets($fp))) {
        echo $line;
    }

    // ファイルを閉じる
    fclose($fp);
}

ポイントとなる、変数、メソッドを説明しておきます。

$argv

コマンドライン引数を、配列の形で保持している。

e.g. ["readline.php", "a.txt", "b.txt"]

※配列の1番目は、PHPスクリプト自体のPATHが入っているので注意!
(シェルスクリプトと同じですね)

$argc

$argv配列の配列長(サイズ)になります。

for ($i = 1; $i < $argc; $i++) {
    $v = $argv[$i];
    ...
}

$argvの1番目は、PHPスクリプト自体のPATHが入っているので、
添字は1から始める事で、引数のみでループする。

fgets

ファイルハンドルから、文字列を読み込むメソッド。
fgets ($handle [, $length ])

第二引数にバッファサイズを指定する事ができます。
指定しない場合、fgetsは、行末(一行ずつ)までを読み取ります。

プロセス置換を使う例

シェルのプロセス置換を利用すると、
PHP側で、わざわざ複数ファイル対応しなくても済みます。

php readline.php <(cat *.txt)

ただ、プロセス置換を利用した場合、
PHPのバージョンが古いと注意しないといけません。

古いPHPバージョンは注意

古いバージョンのPHPで、プロセス置換されたファイルを読み込むと
エラーが発生して、読み込めない。

PHP Warning: fopen(/dev/fd/63): failed to open stream: No such file or directory

これは、PHPのバージョンによるもので、
新しいバージョンであれば発生しません。

一時ファイルを許容するなら

他にも、そんなPHP実装しなくても、
一時ファイルを作成してから、渡すようでもいいでしょう。
ただ、ちょっと面倒ですけどね。

cat *.txt > all.txt
php readline.php all.txt

まとめ

コマンドライン引数で、複数ファイル指定して、
1行ずつ処理する、PHP実装のサンプルを記載しました。

プロセス置換を利用すれば、
PHP側では、単一ファイルの読み込みだけでも事足りるでしょう。
ただ、古いPHPの場合、エラーがでるので注意です。

同じ事を実現したいときに、
他の方法として、
標準入力を受け付けるようにしても、良いかもしれませんね。


PHP プロセス置換のファイルが読み込めない

コメントを残す