PHP 的 feof 行为与 C 的比较

发布于 2024-09-09 11:59:54 字数 936 浏览 5 评论 0原文

我有 C 和 C++ 背景,但也玩过一些网络东西。我们所有的 C 人员(希望)都知道在执行读取之前对 FILE* 调用 feof 是一个错误。这常常让 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 在 PHP 中的 fread 之前?

PHP 可以通过几种不同的方式来完成此操作,但我觉得它们有缺点

  • 他们可以将其默认 。到 !EOF。这是次优的,因为它对于某些极端情况可能不正确。

  • 他们可以在 fopen 调用期间获取文件大小,但这不适用于所有类型的文件资源,从而产生不一致的行为并且速度会更慢。

I come from a C and C++ background but also play with some web stuff. All us C folks (hopefully) know that calling feof on a FILE* before doing a read is an error. This is something that stings newbies to C and C++ very often. Is this also the case for PHP's implementation?

I figure it has to be because the file could be a socket or anything else where it is impossible to know the size before finishing reading. But just about every PHP example (even those found on php.net I've seen looks something like this (and alarms go off in my head):

$f = fopen("whatever.txt", "rb");
while(!feof($f)) {
    echo fgets($f);
}
fclose($f);

I know it is preferable to write this like this and avoid this issue:

$f = fopen("whatever.txt", "rb");
while($line = fgets($f)) {
    echo $line;
}
fclose($f);

but that's besides the point. I tried testing if things would fail if I did it "the wrong way", but I could not get it to cause incorrect behavior. This isn't exactly scientific, but I figured it was worth a try.

So, is it incorrect to call feof before an fread in PHP?

There are a couple of ways that PHP could have done this differently that C's version, but I feel they have downsides.

  • they could have it default to !EOF. This is sub-optimal because it may be incorrect for some corner cases.

  • they could get the file size during an fopen call, but this couldn't work on all types of file resources, yielding inconsistent behavior and would be slower.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

大海や 2024-09-16 11:59:55

在您尝试读取文件之前,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) 不会返回任何数据,并且您对其执行的任何处理都不会很好地处理任何数据。如果您确实需要知道是否位于文件末尾,则必须先进行读取。

PHP doesn't know whether it's at the end of the file until you've tried to read from it. Try this simple example:

<?php 
$fp = fopen("/dev/null","rb"); 
while (!feof($fp)) { 
    $data = fread($fp, 1);
    echo "read " . strlen($data) . " bytes";  
} 
fclose($fp); 
?>

You will get one line reading read 0 bytes. feof() returned true even though you were technically at the end of the file. Usually this doesn't cause a problem because fread($fp, 1) returns no data, and whatever processing you're doing on that handles no data just fine. If you really do need to know if you're at the end of the file, you do have to do a read first.

朦胧时间 2024-09-16 11:59:55

这可能更像是一个问题而不是答案,但为什么不使用 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:[email protected]/file.txt", $real_content, 0, $stream);
}

那么你不需要担心 EOF 或任何事情,它会为你做这件事(ftp put 有点冒险,但没关系)。当然,这并不是在所有情况下都有效......

我在最初的问题中是否遗漏了一些东西,导致这种方法不可行?

This may be more of a question than an answer, but why not use file_get_contents()? In my experience, if you are reading a file or a stream, this function does the dirty work for you (assuming you want to read the entire resource to a string, or know/can compute a limit and offset). Its sister function file_put_contents() works well, in reverse.

For instance, here's an example:

$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);
}

or a stream:

$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:[email protected]/file.txt", $real_content, 0, $stream);
}

Then you don't need to worry about EOF or anything, it does it for you (ftp put gets a bit dicey, but that's ok). Of course, this won't work in all situations...

Is there something that I'm missing from the original question that makes this approach unfeasible?

回忆躺在深渊里 2024-09-16 11:59:55

您关于在 fread 之前不调用 feof 的断言不正确 - 因此该问题无效。

Your assertion about not calling feof before an fread is not correct - consequently the question is not valid.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文