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 не правильно - следовательно, вопрос не является действительным.

Другие вопросы по тегам