PHP поведение feof против C
Я из C и C++, но также играю с некоторыми вещами в Интернете. Все мы, народ C (надеемся), знаем, что зовем feof
на FILE*
перед чтением это ошибка. Это то, что очень часто вызывает у новичков С и С ++. Это также относится и к реализации PHP?
Я полагаю, что это должно быть потому, что файл может быть сокетом или чем-то еще, где невозможно узнать размер до окончания чтения. Но почти каждый пример PHP (даже те, что были найдены на php.net, который я видел, выглядят примерно так (и тревоги у меня в голове):
$f = fopen("whatever.txt", "rb");
while(!feof($f)) {
echo fgets($f);
}
fclose($f);
Я знаю, что лучше написать это так и избежать этой проблемы:
$f = fopen("whatever.txt", "rb");
while($line = fgets($f)) {
echo $line;
}
fclose($f);
но это не главное. Я попытался протестировать, если что-то не получится, если я сделаю это "неправильным образом", но я не смог заставить его вызвать неправильное поведение. Это не совсем научно, но я решил, что стоит попробовать.
Итак, это неправильно, чтобы позвонить feof
перед fread
в PHP?
Есть несколько способов, которыми PHP мог бы сделать это иначе, чем версия C, но я чувствую, что у них есть недостатки.
по умолчанию они могут иметь значение!EOF. Это неоптимально, потому что это может быть неправильно для некоторых угловых случаев.
они могли бы получить размер файла во время
fopen
вызов, но это не может работать на всех типах файловых ресурсов, приводя к противоречивому поведению и будет медленнее.
3 ответа
PHP не знает, находится ли он в конце файла, пока вы не попытаетесь прочитать его. Попробуйте этот простой пример:
<?php
$fp = fopen("/dev/null","rb");
while (!feof($fp)) {
$data = fread($fp, 1);
echo "read " . strlen($data) . " bytes";
}
fclose($fp);
?>
Вы получите одну строку чтения read 0 bytes
, feof() вернул true, хотя технически вы были в конце файла. Обычно это не вызывает проблем, потому что fread($fp, 1)
не возвращает данных, и любая обработка, которую вы выполняете, не обрабатывает данные. Если вам действительно нужно знать, находитесь ли вы в конце файла, вы должны сначала прочитать.
Это может быть скорее вопрос, чем ответ, но почему бы не использовать file_get_contents ()? По моему опыту, если вы читаете файл или поток, эта функция делает грязную работу за вас (предполагая, что вы хотите прочитать весь ресурс в строку, или знаете / можете вычислить предел и смещение). Его сестринская функция file_put_contents() работает хорошо, в обратном порядке.
Например, вот пример:
$expected_content = "Hello Stack Overflow!"
$real_content = file_get_contents("/path/to/file.txt");
if ($expected_content != $real_content){
file_put_contents("/path/to/file.txt", $real_content);
}
или поток:
$expected_content = "Hello Stack Overflow!"
$real_content = file_get_contents("http://host.domain.com/file.txt");
if ($expected_content != $real_content){
$options = array('ftp' => array('overwrite' => true));
$stream = stream_context_create($options);
file_put_contents("ftp://user:pass@host.domain.com/file.txt", $real_content, 0, $stream);
}
Тогда вам не нужно беспокоиться о EOF или о чем-то другом, он делает это за вас (ftp put немного рискован, но это нормально). Конечно, это не будет работать во всех ситуациях...
Есть ли что-то, что я упускаю из первоначального вопроса, который делает этот подход неосуществимым?
Ваше утверждение о том, чтобы не звонить feof
перед fread
не правильно - следовательно, вопрос не является действительным.