过去几天我一直在研究一个奇怪的 PHP 问题,其中 feof() 函数在文件结束之前返回 true。下面是我的代码的骨架:
$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
}
}
通过大量测试,我发现该程序在除一个文件之外的所有内容上都可以正常工作:
- 该文件存储在本地驱动器上。
- 这个文件大约有 800 万行长,平均每行大约 200-500 个字符。
- 它已经被清理过,并用十六进制编辑器仔细检查,没有发现异常字符。
- 当程序认为它已经到达文件末尾时(即使它还剩下大约 800K 行),程序在第 7172714 行始终失败。
- 我已经在每行字符较少但在 20-30 百万行之间没有问题的文件上测试了该程序。
- 我尝试从http://php.net/manual/en/function.fgets.php上的评论中运行代码,以查看是否是我的代码中的某些内容导致了问题,而第 3 方代码同样失败线。编辑:还值得一提的是,第 3 方代码使用 fread() 而不是 fgets()。
- 我尝试在 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 行。似乎问题是由于某种原因,行被跳过并且未被读取。所有换行符都存在。