Вопрос
Я имею опыт работы с C и C++, но также играю с некоторыми веб-материалами.Все мы, ребята из C (надеюсь), знаем, что призвание feof
на FILE*
перед чтением возникает ошибка.Это то, что очень часто беспокоит новичков в C и C++.Это также относится к реализации 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
вызов, но это не могло работать со всеми типами файловых ресурсов, что приводило к нестабильному поведению и было бы медленнее.
Решение
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
неверно - следовательно вопрос некорректен.