PHP поведение feof против C - PullRequest
6 голосов
/ 13 июля 2010

Я из 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 ]

3 голосов
/ 13 июля 2010

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) не возвращает данных, и любая обработка, с которой вы работаете, не обрабатывает данные.Если вам действительно нужно знать, находится ли вы в конце файла, вам сначала нужно выполнить чтение.

0 голосов
/ 13 июля 2010

Это может быть больше вопрос, чем ответ, но почему бы не использовать 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 пут становится немного рискованным, но это нормально). Конечно, это не будет работать во всех ситуациях ...

Есть ли что-то, чего я упускаю из первоначального вопроса, который делает такой подход неосуществимым?

0 голосов
/ 13 июля 2010

Ваше утверждение о том, что вы не должны звонить feof до fread, неверно - следовательно, вопрос недействителен.

...