一个已经打开的 FILE 句柄是否可以在不重新打开它的情况下反映对基础文件的更改?

Can an already opened FILE handle reflect changes to the underlying file without re-opening it?

假设一个纯文本文件,foo.txt,和两个进程:

在 C 程序中,在初始 fopen() 之后保持 FILE* fp 打开,执行 rewind() 并再次读取似乎没有反映文件发生的变化同时。是通过 fclose()fopen() 循环查看更新内容的唯一方法,还是有办法重新使用已经打开的 FILE 句柄,但读取最近写入的内容数据?

对于上下文,我只是想找到最有效的方法。

在 Unix/Linux 上,当您使用已存在的名称创建文件时,不会以任何方式删除或更改旧文件。创建了一个新文件,目录 更新为指向新文件而不是旧文件。

只要某些目录入口指向旧文件(Unix 文件系统允许多个目录指向同一个文件)或某些程序具有该文件的打开文件句柄,旧文件将继续存在,这与您的问题更相关。

只要您不关闭 fp,它就会继续引用原始文件,即使文件系统不再引用该文件。当您关闭 fp 时,该文件将自动进行垃圾收集,而下次您打开 foo.txt 时,您将获得一个文件描述符,该文件描述符代表当时碰巧具有该名称的任何文件。

简而言之,对于您指定的 shell 脚本,您的 C 程序必须关闭并重新打开文件才能看到新内容。

理论上,shell 脚本可以覆盖同一个文件而不删除它,但是 (a) 这很难做到正确; (b) 它容易出现竞争条件; (c) 关闭和重新打开文件不是 time-consuming。但如果你这样做,你会看到变化。 [注1]

特别是,附加到现有文件是很常见的(也很容易),如果你有一个 shell 脚本可以做到这一点,你可以保留打开文件描述符并查看更改。但是,在那种情况下,您通常会在追加新数据之前读取到文件末尾,并且标准 C 库将 feof() 指示符视为粘性;一旦设置好,您将继续从新读取中获得 EOF 指示。如果您怀疑某些进程将向文件写入更多数据,您应该在重试读取之前使用 fseek(fp, 0, SEEK_CUR); 重置 EOF 指示。

备注

  1. 正如 @amadan 在评论中指出的那样,echo text > foo.txt 也存在竞争条件,尽管 window 更短一些。但是你绝对可以通过使用惯用语 echo text > temporary_file; mv -f temporary_file foo.txt 来避免竞争条件,因为重命名操作是原子的。当然,这肯定需要您关闭并重新打开文件。但这是一个好主意,尤其是当正在写入的内容很长或很关键,或者如果经常创建新文件时。