O_TRUNC 和 O_APPEND 需要一起使用吗?

Is it required to use O_TRUNC and O_APPEND together?

我正在阅读这本书 The Linux Programming Interface。在第 4 章的第 73 页上, 它是这样写的:

fd = open("w.log", O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, S_IRUSR | S_IWUSR);

我读到 O_TRUC 标志用于将文件长度截断为零,这会破坏文件中的任何现有数据。

O_APPEND标志用于将数据追加到文件末尾。

内核记录了一个file offset,有时也称为read-write offset or pointer。这是文件中下一个 read()write() 开始的位置。

我很困惑,如果文件被截断并且内核在文件末尾进行后续写入,为什么需要追加标志来明确告诉在文件末尾追加?

没有附加标志(如果文件被截断),内核在文件末尾写入以供后续 write() 函数调用。

两者是完全独立的。该文件只是用 O_APPEND 打开,因为它是一个日志文件。

作者希望并发消息连接起来而不是相互覆盖(例如,如果程序分叉),并且如果管理员或日志轮换工具截断了文件,那么新消息应该从第 1 行开始写入,而不是#1000000 行最后一个日志条目被写入。没有 O_APPEND.

就不会发生这种情况

O_APPEND flag is used to append data to the end of the file.

确实如此,但不够完整,可能会产生误导。而且我怀疑您实际上在这方面感到困惑。

The kernel records a file offset, sometimes also called the read-write offset or pointer. This is the location in the file at which the next read() or write() will commence.

这也不完整。至少每个可搜索文件都有一个文件偏移量。那是下一个 read() 开始的位置。这是下一个 write() 将开始的地方 如果文件未在追加模式下打开 ,但在追加模式下 每个 写入发生在文件末尾,就好像在每个文件之前用 lseek(fd, 0, SEEK_END) 重新定位一样。那么,在那种情况下,当前文件偏移量可能不是下一个 write() 开始的位置。

I am confused that if the file is truncated and the the kernel does the subsequent writing at the end of the file why the append flag is needed to explicitly tell to append at the end of the file ?

不需要在文件末尾发生截断后第一次写入(由任何进程),因为在文件被截断后立即没有'其他任何位置。

With out the append flag (if the file is truncated), the kernel writes at the end of the file for the subsequent write() function call.

后续写入也不需要,只要文件没有被重新定位或外部修改。否则,下一次写入的位置取决于文件是否以追加模式打开。

在实践中,不一定每个标志组合都是有用的,但是 O_TRUNCO_APPEND 的组合与没有另一个标志的效果明显不同,并且该组合在某些情况下很有用。

O_APPEND 对于 O_TRUNC 很少有意义。我认为 C fopen 模式的组合不会产生这种组合(在 POSIX 系统上,这是相关的)。

O_APPEND 确保无论写入位置如何,每次写入都自动在文件末尾完成。特别是,这意味着如果多个进程正在写入文件,它们不会互相干扰。

note that POSIX does not require the atomic behavior of O_APPEND. It requires that an automatic seek takes place to the (current) end of the file before the write, but it doesn't require that position to still be the end of of the file when the write occurs. Even on implementations which feature atomic O_APPEND, it might not work for all file systems. The Linux man page on open cautions that O_APPEND doesn't work atomically on NFS.

现在,如果每个进程在打开文件时都使用 O_TRUNC,它将破坏所有其他进程写入的所有内容。这与进程不应该破坏彼此的写入的想法相冲突,为此指定了 O_APPEND

O_APPEND 不需要被理解为唯一写入者的单个进程附加到文件。可以只搜索到最后然后开始写入新数据。有时 O_APPEND 只是因为它是一种编程快捷方式而在排他情况下使用。我们不必费心额外调用定位到文件末尾。比较:

FILE *f = fopen("file.txt", "a");
// check f and start writing

对比:

FILE *f = fopen("file.txt", "r+");
// check f
fseek(f, 0, SEEK_END); // go to the end, also check this for errors
// start writing

我们可以考虑这样的想法,我们有一组进程使用 O_APPEND 到一个文件,这样第一个进程也执行 O_TRUNC 来首先截断它。但是这样编程似乎很尴尬;一个进程很难判断它是否是第一个打开文件的进程。

如果需要这样的情况,比方说,启动时,由于某种原因,启动前的旧文件不相关,只需执行启动时操作(脚本或其他)删除之前的旧文件这些多个进程被启动。然后每个人在必要时使用 O_CREAT 创建文件(如果它是第一个进程)但不使用 O_TRUNC (如果它们不是第一个进程),并使用 O_APPEND做原子的(如果可用的话)附加东西。