PHP 中的 fopen 模式 “r+” 和 “rw+” 有什么区别?

2022-08-30 09:31:16

Stack Overflow中的许多答案都使用,但手册没有列出模式,只有模式(或模式)。fopen($file, "rw+")"rw+""r+""w+"

所以我想知道,“rw+”模式是做什么的?fopen($file,“rw+”或“r+”有什么区别?我问这个是因为没有关于模式的文档。"rw+"

一种方法是考虑模式是累加的,但我在手册页中找不到任何关于组合模式的提及(此外,如果已经使其可读,那么与 组合有什么意义?)。但最重要的是,w+模式截断文件,而rw+不会截断它(因此,它们不能是累加的)。可能没有模式,尽管Stack Overflow用户使用它。也许它之所以有效,是因为解析器忽略了“w”字母,因为模式似乎是===?fopen"r""w+""w+"rw+rw+r+

为了澄清我的问题:什么是“rw+”模式,也就是说,它与其他模式有何不同?我在评论中只收到了两个答案:要么我应该检查文档(我已经检查并重新检查过)和一个错误的答案,它说它等于(它不是)。 截断文件,而不截断文件。"w+""w+""rw+"

这是一个用于测试的脚本(它证明截断文件,但不会):w+rw+

<?php 
$file = "somefile"; 
$fileOpened = fopen($file, "w"); 
fwrite($fileOpened, "0000000000000000000"); 
fclose($fileOpened);  

$fileOpened = fopen($file, "rw+"); 
fwrite($fileOpened, "data"); 
fclose($fileOpened); 
$fileOpened = fopen($file, "r"); 
$output = fgets($fileOpened); 
echo "First, with 'rw+' mode:<br>".$output; 

$fileOpened = fopen($file, "w+"); 
fwrite($fileOpened, "data"); 
fclose($fileOpened); 
$fileOpened = fopen($file, "r"); 
$output = fgets($fileOpened); 
echo "<br><br><br>Now with only 'w+' mode:<br>".$output; 
?>

答案 1

我想你已经差不多弄清楚了。虽然我猜,你想要权威的答案。

确实,文档没有提到 。然而,还有更好的东西:PHP源代码"rw+"


兔子洞

我很难尝试浏览源代码,直到我找到PHP开发人员的PHP源代码系列(第1部分第2部分第3部分第4部分)。我知道两个网站之间的链接跳跃,这个系列就像那样时髦。顺便说一句,我没有找到宣布的第5部分。

注意:这些文章很旧,他们谈论的是 PHP 5.4。

让我们看看实际上做了什么...让我们掉进兔子洞...fopen

首先,我们看一下函数定义(我根据上面链接的第2部分的建议找到了它)。我注意到它使用了php_stream_open_wrapper_ex,这是我在其他地方找到的,它只是使用了我们在stream.c中找到的。_php_stream_open_wrapper_ex

用 什么做 ?它将其传递给stream_opener_php_stream_open_wrapper_exmode

寻找 的定义将我带到了 php_streams.h 中的类型 php_stream_wrapper_opsstream_opener

搜索php_stream_wrapper_ops类型的用法使我找到了plain_wrapper.c

实际上有很多初始化允许打开不同的东西。我们正在研究php_fopen_wrapper.c,因为它具有 where is 的初始化。php_stream_wrapper_opsphp_stream_wrapper_opsstream_openerphp_plain_files_stream_opener

我们正在到达那里...

php_plain_files_stream_opener在同一文件中进一步向下它委托给php_stream_fopen_rel

php_streams.h 使用 定义php_stream_fopen_rel。这又回到了plain_wrapper_php_stream_fopen

最后,_php_stream_fopen打电话给php_stream_parse_fopen_modes。这将采取字符串并输出一些标志,耶!


仙境

让我们来看看php_stream_parse_fopen_modes

PHPAPI int php_stream_parse_fopen_modes(const char *mode, int *open_flags)
{
    int flags;

    switch (mode[0]) {
        case 'r':
            flags = 0;
            break;
        case 'w':
            flags = O_TRUNC|O_CREAT;
            break;
        case 'a':
            flags = O_CREAT|O_APPEND;
            break;
        case 'x':
            flags = O_CREAT|O_EXCL;
            break;
        case 'c':
            flags = O_CREAT;
            break;
        default:
            /* unknown mode */
            return FAILURE;
    }

    if (strchr(mode, '+')) {
        flags |= O_RDWR;
    } else if (flags) {
        flags |= O_WRONLY;
    } else {
        flags |= O_RDONLY;
    }

#if defined(O_CLOEXEC)
    if (strchr(mode, 'e')) {
        flags |= O_CLOEXEC;
    }
#endif

#if defined(O_NONBLOCK)
    if (strchr(mode, 'n')) {
        flags |= O_NONBLOCK;
    }
#endif

#if defined(_O_TEXT) && defined(O_BINARY)
    if (strchr(mode, 't')) {
        flags |= _O_TEXT;
    } else {
        flags |= O_BINARY;
    }
#endif

    *open_flags = flags;
    return SUCCESS;
}

对于抽象,这就是它的作用(忽略细节):

  1. 它采用 的第一个字符,并检查它是否为 、 、 、 、 。如果它识别其中任何一个,它将设置相应的标志。否则,我们有一个.moderwaxcFAILURE

  2. 它查找字符串中的某个位置并设置相应的标志。+

  3. 它在字符串中的某个位置查找 和 (取决于预处理器指令),并设置相应的标志。ent

  4. 返回。SUCCESS


回到现实世界

你问:

PHP 中的 fopen 模式 “r+” 和 “rw+” 有什么区别?

无。PHP 只关心字符串以 开头并带有 .将被忽略。"r""+""w"

最后一点:虽然玩弄它并写出类似的东西很诱人,但要小心,因为这些字母有一天可能会有意义。它不会向前兼容。事实上,在某些语境中,已经有了意义。相反,我建议,坚持使用文档。"read+""e"


感谢您找个借口来看看PHP源代码。


答案 2

推荐