在Linux系统上打开文件的行为如何?


17

我只是将日志文件重命名为“ foo.log.old”,并假定应用程序将开始在“ foo.log”处写入新的日志文件。我很惊讶地发现它跟踪日志文件到其新名称,并不断在“ foo.log.old”中追加行。

在Windows中,我不熟悉这种行为-我不知道是否有可能实现它。如何在Linux中实现此行为?在哪里可以了解更多信息?


我并不是要回答这个问题,因为我真的不知道,但是我认为这与在移动文件时不更改索引节点有关。
mathepic 2011年

Answers:


20

程序通过文件系统维护的编号(在传统的UNIX文件系统上称为inode)连接到文件,名称仅是对其的引用(可能不是唯一的引用)。

有几件事要注意:

  1. mv除非在文件系统之间移动文件,否则使用来移动文件不会更改该下标编号(等同于在原始文件上使用cpthen rm)。
  2. 因为一个文件可以连接多个名称(即,我们具有硬链接),所以“删除”文件中的数据不会消失,直到对基础文件的所有引用都消失了。
  3. 也许最重要:当程序为open文件时,它引用该文件(对于删除数据的目的而言)等同于具有连接到文件名的文件。

这引起了以下几种行为:

  • 程序可以open读取文件,但直到用户rm在命令行上对其进行编辑后才可以实际读取文件,并且该程序仍然可以访问数据
  • 您遇到的一个问题:mv生成文件并不会断开文件与打开该文件的任何程序之间的关系(除非您跨越文件系统边界,在这种情况下,该程序仍具有原始版本可以使用)。
  • 如果程序已经open编写了一个文件来写入文件,并且用户rm在命令行中使用了文件的最后一个文件名,则该程序可以继续将内容直接放入文件中,但是一旦关闭,就不再有对该数据的引用,并且它会消失。
  • 通过一个或多个文件进行通信的两个程序可以通过在完成文件后删除文件来获得粗略的部分安全性open。(这不是真正的安全思想,它只是将一个巨大的漏洞转换为竞争条件。)

1
我同意@dmckee,我只想指出:程序可以open读取和写入文件(问题中的日志文件发生了什么)。
jsbillings 2011年

@jsbillings:是的,但是有风险。如果所有文件系统名称都消失了,则可以将GB写入打开的文件,一旦关闭它,该文件将像晨露一样蒸发。
dmckee 2011年

1
同样,将索引节点复制到内核中,而不是磁盘副本,这就是操作对象。因此,该文件可以是mv'd或cp',但是一个打开的文件已经在使用内核数据结构,而不是磁盘版本。因此,如果将另一个文件复制到可以写入的文件中,则该过程仍将写入与旧文件相同的相对位置。这就是为什么程序(例如Apache httpd)具有一个信号处理程序来关闭并重新打开日志文件的原因。
弓箭2011年

0

要真正了解这种行为是如何实现的,可以看一些Unix编程书籍。Mathepic是正确的,因为它与inode有关。实际的路径名仅用于打开文件,一旦完成,程序将通过其打开的文件描述符对其进行引用。文件描述符反过来引用索引节点,在这种情况下,索引节点并不关心基础文件名称是否已更改。

至于在Windows中实现这一点,这是另一个站点的问题。

要了解更多有关此方面的知识而又不打书,只需搜索linux文件系统和inode。可能没有一个明确的答案,但是您将能够理解原因。


4
“四处搜寻-您可能找不到一个好的答案,但会理解的”不是一个好的答案。
mattdm 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.