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

fle*_*len 57 php fopen

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

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

一种方法是考虑所述模式为添加剂,但我找不到在结合模式的任何提及fopen手册页(此外,什么是相结合的意义"r""w+",如果"w+"已经使其可读?).但最重要的是,w+模式截断文件,rw+而不截断它(因此,它们不能是加法的).rw+尽管Stack Overflow用户使用它,但可能没有模式.也许它有效,因为解析器忽略了"w"字母,因为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; 
?>
Run Code Online (Sandbox Code Playgroud)

The*_*aot 68

我想你几乎已经弄明白了.虽然我猜,你想要权威的答案.

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


兔子洞

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

注意:那些文章很旧,他们在讨论PHP 5.4.

让我们看看究竟fopen做了什么......让我们陷入兔子洞......

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

怎么_php_stream_open_wrapper_exmode它将它传递给stream_opener.

寻找定义stream_opener带我到php_stream_wrapper_opsphp_streams.h中的类型.

搜索该类型的用途导致php_stream_wrapper_ops我使用plain_wrapper.c.

实际上有很多初始化php_stream_wrapper_ops允许打开不同的东西.我们正在php_fopen_wrapper.c因为它有一个初始化php_stream_wrapper_ops哪里stream_openerphp_plain_files_stream_opener.

我们到了那里......

php_plain_files_stream_opener在同一个文件进一步下跌.它委托给php_stream_fopen_rel.

php_streams.hphp_stream_fopen_rel通过使用定义_php_stream_fopen.这是关于plain_wrapper.c的.

最后,_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;
}
Run Code Online (Sandbox Code Playgroud)

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

  1. 它采用的第一个字符mode并检查它是否是r,w,a,x,c.如果它识别出任何一个,它会设置适当的标志.否则我们有一个FAILURE.

  2. +在字符串中的某处查找并设置适当的标志.

  3. 它会查找e,nt(取决于预处理器指令)的字符串的地方,并设置相应的标志.

  4. 返回SUCCESS.


回到现实世界

您询问:

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

没有.PHP只关心字符串的开头"r"并且有一个"+".该"w"被忽略.

最后的注意事项:尽管玩它很有吸引力并写下类似的东西"read+",但要小心,因为那些字母有一天会有一些意义.它不会向前兼容.事实上,在某些情况下,"e"已经有了意义.相反,我建议,坚持文档.


感谢借口来看看PHP源代码.

  • 所以从技术上讲,你可以传递`"read +"`,或`rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr (11认同)
  • 只有不包含"e","n"或"t"的单词等同于普通的"r".所以`"rrrrrrrrrrrrr"是的,但是``读'或者@Theraot的任何一个或@Nisse的建议,没有.除非你确实想要额外的标志. (5认同)
  • 我知道我应该避免"谢谢"评论,但这个答案很棒,非常感谢你!它还揭示了其他语言(例如,C,我认为解析器也忽略了"w"https://adelekeadelaja.blogspot.com.br/2015/06/c-programming-file-rw-mode-not -working.html),我认为人们自然会选择"rw",因为它更直观地想到"读写",但他们忘记了加号(我认为普遍的"w +"意味着"读").但我离题了,再次感谢! (5认同)
  • `"兔子,白色","红色女王",""rapunzel"`,"rumpelstiltskin"`...... (3认同)