默认的写入行为是O_TRUNC还是O_APPEND?

12
当你以访问模式 O_WRONLYO_RDWR 打开一个文件时,默认行为是什么?文件是在附加模式还是截断模式下打开的?根据man页面

标志参数必须包括以下访问模式之一:O_RDONLY、O_WRONLY或O_RDWR。
...
此外,可以将零个或多个“文件创建”标志和“文件状态”标志与标志按位或。

这听起来像是O_APPENDO_TRUNC标志是可选的。那么下面的代码会做什么呢?

void main ( void )
{
    int fd = open( "foo.txt", O_WRONLY );

    write( fd, "hello", 5 );

    close( fd );
}

你本可以试着自己解决,而不是直接问别人。此外,由于这些位被进行了OR运算,根据手册,只需查看两个定义的值(或询问调试器),并查看哪个为零即可。 - Frank Merrow
3
感谢您在公共论坛上提出这个问题,让其他人也能从中学习并获得答案,@Jet-Blue。 - Semicolon
2个回答

17

都不是。

  • 默认情况下,文件打开时光标位于开头。写入会覆盖文件开头的字节。

  • O_TRUNC选项会在文件存在时将其截断。

  • O_APPEND选项会使写入追加到文件末尾而不是覆盖开始。此标志是持久的。如果你移动光标到其他位置读取数据,在每次写入之前它总是重新定位到文件末尾。

这些标志是正交的,不相互排斥。甚至可以组合它们,以便最初截断文件并确保所有后续写入总是追加。


3
请注意,根据 POSIX,您可以使用 pwrite() 将数据写入文件的任何位置,即使该文件使用 O_APPEND 打开:“pwrite() 函数与 write() 等效,只是它写入给定位置并且不更改文件偏移量(无论是否设置了 O_APPEND)。” 这允许使用 O_APPEND 打开的文件在原子方式下将数据追加或以原子方式写入任意偏移量。不幸的是,在 Linux 上,pwrite() 存在缺陷。 - Andrew Henle
@AndrewHenle:谢谢你提醒我!自从我第一次听说这个WONTFIX bug以来,我就一直很生气,现在有了一个带有标志参数的pwritev2系统调用,我认为它终于可以修复而不会破坏内核API稳定性。未经测试的补丁添加了一个选项,用户空间的pwrite函数可以传递以修复它:http://ix.io/28aG - R.. GitHub STOP HELPING ICE

6

当独自使用 O_WRONLY 标志时,它会打开文件进行写操作,保留现有的文件内容,并将文件指针定位在文件的开头。任何写入操作都会覆盖现有内容。

如果您使用 lseek 重新定位文件指针,则后续写入操作将发生在重新定位的偏移量处。

这种行为与 O_TRUNC 相反,后者在打开文件时截断文件内容,与 O_APPEND 相反,后者强制所有写入操作发生在文件末尾。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接