当您读取一个被覆盖的文件时会发生什么?

当您读取一个被覆盖的文件时会发生什么?

假设我读取(cat)一个文件,而另一个进程正在重写其内容。输出是可预测的吗?会发生什么?

答案1

这取决于作者做什么。

如果写入者覆盖现有文件,那么当写入者超过读取器(如果有的话)时,读取器将看到新内容。如果作者和读者以不同的速度进行,读者可能会交替看到旧内容和新内容。

如果写入器在开始写入之前截断文件,则读取器将在此时针对文件末尾运行。

如果写入器创建一个新文件,然后将新文件移动到旧名称,则读取器将继续从旧文件中读取。如果移动或删除打开的文件,则打开该文件的进程会继续读取同一文件。如果文件被删除,它实际上保留在磁盘上(但无法再次打开它),直到最后一个进程将其关闭。

Unix系统往往没有强制的。如果应用程序想要确保其写入器组件和读取器组件不会互相干扰,则开发人员需要使用适当的锁定。有一些例外情况,内核打开的文件可能会受到保护,不被用户应用程序写入,例如环形- 已安装的文件系统映像或在某些 UNIX 变体上执行的可执行文件。

答案2

这是一种经典的竞争条件,因此根据定义,结果是不可预测的。

其中,这取决于

  • fopen(3)open(2)写入模式,
  • 写入器是否缓冲其输出,如何缓冲,
  • 读者如何阅读文件,
  • 读者和作者之间的速度差异,
  • 读取和写入开始之间的时间差。
  • 当然,在现代多核机器上,由于其他较低因素(例如进程调度),事情变得更加复杂。

如果您需要能够在重写文件时读取该文件,那么您可以让编写器制作该文件的临时副本,对其进行修改,然后将其复制回原始文件。rsync例如,这种方式就是这样做的。有很多方法可以实现这一点,但没有免费的午餐。每种方法都有其自身的缺点和影响。

答案3

以前的回复者有比这更全面的解释,但这里有一个绝对有效的技巧,几乎完全按照他想要的做:

$ tail -f <filename>

将在写入时向您显示文件的结尾。例如,如果您想将 STDERR 通过管道传输到文件,但仍可以在另一个终端窗口中看到它,那么这很方便。

相关内容