想知道是否有办法验证文件是否未在运行时写入或已被其他进程打开。最好是一种适用于所有操作系统的方法
答案 0 :(得分:1)
不一般。
用于检测和阻止使用或更改另一个进程正在使用的文件的最普遍的一般应用程序级机制是file locking
没有跨平台解决方案的一个原因是某些操作系统提供协同锁定,其中文件锁是建议性的。例如,大多数Unix变种和Linux。
因此,在这些平台上,您只能保证使用其他进程事先知道使用特定类型的咨询锁的文件来了解其他进程。
这些平台中的大多数确实具有强制锁定功能。它是基于每个文件设置的,作为文件属性的一部分。这有一些问题(例如竞争条件)。
所以不,可以提供您所寻求的验证的基本机制是非常不同的。在Go中提供可靠的跨平台机制可能会非常麻烦,可以保证在其他流程可能不合作的各种流行平台上工作。
参考
答案 1 :(得分:1)
这不会回答你的问题,但由于我们可能在这里处理XY problem,我想从PoV看待问题与锁定不同,否则检测文件没有被写入:一个 update-then-rename-over 方法,这是对文件进行原子更新的唯一合理方法,这是(新手)程序员遗憾地不为人所知。
由于文件系统本质上是活泼的,为了确保正确的“数据库”工作与文件 - 每个人都看到文件内容的一致状态, - 你必须使用锁定或原子更新或两者兼而有之。
要以原子方式更新文件的内容,请执行以下操作:
在所有当代商品操作系统上保证重命名是原子的,这样当一个进程试图打开一个文件时,它会打开一个旧的副本或新的副本,但不会打开它们之间的东西。
在POSIX系统上,Go的os.Rename()
一直是原子的,因为它最终会调用rename(2)
;从Go 1.5开始,在Windows it was fixed上。
请注意,此方法仅提供文件内容的一致性 从某种意义上说,没有两个进程最终会同时更新它 但它不能确保只能确保“序列化”更新 通过锁定或其他“侧通道”信令。 也就是说,通过原子更新,仍然可能出现这种情况:
文件的内容将是一致的,但状态将是什么 进程最后调用操作系统的重命名API函数。
因此,如果您需要序列化,则需要锁定。
我担心Go没有跨平台文件锁定解决方案 (无论如何,即使在Unix-y系统中,锁定方法也有很大差异 - 更不用说Windows了;请参阅this以获得有趣的阅读内容,但其中一种方法是使用特定于平台的内容 锁定在上面步骤(2)中创建的临时文件。
更新文件的方法然后更改为:
使用众所周知的名称打开一个临时文件。
如果要更新的文件名为“foo.state”,请将其命名为“foo.state.lock”。
使用任何特定于平台的锁定锁定它。
如果锁定失败,这意味着另一个进程正在更新文件, 所以退出或等待 - 这真的取决于你所追求的目标。
一旦锁定,请读取文件的数据。
修改它,重新写入被此数据锁定的临时文件。
将临时文件重命名为原始文件。
关闭温度。提起并释放锁。