ここ数日、ファイルの終わりの前に feof() 関数が true を返すという奇妙な PHP の問題に取り組んでいます。以下は私のコードのスケルトンです:
$this->fh = fopen("bigfile.txt", "r");
while(!feof($this->fh))
{
$dataString = fgets($this->fh);
if($dataString === false && !feof($this->fh))
{
echo "Error reading file besides EOF";
}
elseif($dataString === false && feof($this->fh))
{
echo "We are at the end of the file.\n";
//check status of the stream
$meta = stream_get_meta_data($this->fh);
var_dump($meta);
}
else
{
//else all is good, process line read in
}
}
多くのテストを通じて、プログラムは 1 つのファイルを除いてすべて正常に動作することがわかりました。
- ファイルはローカル ドライブに保存されます。
- このファイルは約 800 万行の長さで、平均して 1 行あたり約 200 ~ 500 文字です。
- クリーニング済みで、ヘキサエディタで精査したところ、異常な文字は見つかりませんでした。
- プログラムは、ファイルの最後に達したと思われる場合 (約 800K 行が残っているにもかかわらず)、7172714 行で一貫して失敗します。
- 1 行あたりの文字数が少ないが 2000 万から 3000 万行のファイルでプログラムをテストしましたが、問題はありませんでした。
- http://php.net/manual/en/function.fgets.phpのコメントからコードを実行してみましたが、問題を引き起こしているのが自分のコードの何かであり、サードパーティのコードが同じで失敗したかどうかを確認するためだけですライン。編集: サードパーティのコードが fgets() の代わりに fread() を使用したことも言及する価値があります。
- fgets 関数でいくつかのバッファ サイズを指定しようとしましたが、どれも違いはありませんでした。
var_dump($meta) からの出力は次のとおりです。
array(9) {
["wrapper_type"]=>
string(9) "plainfile"
["stream_type"]=>
string(5) "STDIO"
["mode"]=>
string(1) "r"
["unread_bytes"]=>
int(0)
["seekable"]=>
bool(true)
["uri"]=>
string(65) "full path of file being read"
["timed_out"]=>
bool(false)
["blocked"]=>
bool(true)
["eof"]=>
bool(true)
}
ファイルの終わりの前に feof が true を返す原因を突き止めようとすると、次のいずれかを推測する必要があります。
A) 何かが原因で fopen ストリームが失敗し、何も読み取れません (feof が true を返す)
B) いっぱいになって大混乱を引き起こしているバッファがどこかにある
C) PHP の神々は怒っている
他の誰かがこの問題を抱えているかどうかを広く検索しましたが、ファイルがバイナリ モードではなくテキスト モードで読み込まれ、問題を引き起こしていた C++ 以外のインスタンスを見つけることができませんでした。
更新: 読み取り関数が繰り返された回数と、その横にあるエントリに関連付けられたユーザーの一意の ID を常にスクリプトに出力させました。スクリプトは 7175502 のうちの 7172713 行の後でまだ失敗していますが、ファイル内の最後のユーザーの一意の ID が 7172713 行に表示されています。問題は、何らかの理由で行がスキップされて読み取られていないようです。すべての改行が存在します。