如果文件已经存在,我想覆盖它。如果它不存在,我想创建它并写入它。我不喜欢使用第三方库,如lockfile(它似乎可以处理所有类型的锁定)
我最初的想法是:
- 写入一个随机生成的大id的临时文件,以避免冲突
- 重命名临时文件名->新路径名
os.Rename
调用syscall.Rename
,对于Linux/unix使用重命名系统调用(这是原子*)。在Windows上,syscall.Rename
调用MoveFileW
,假设源和目标在同一设备上(可以安排)并且文件系统是NTFS(通常是这种情况)是原子*。
我会注意确保源和目标在同一设备上,这样Linux重命名就不会失败,而Windows重命名实际上是原子的。正如Dave C上面提到的,在与现有文件相同的目录中创建临时文件(通常使用ioutil.TempFile
)是可行的方法;这就是我如何做我的原子重命名。
这在我的用例中适用:
- One Go进程获取更新并重命名文件以交换更新。
- 另一个Go进程正在使用fsnotify监视文件更新,并在更新时重新映射文件。
在上面的用例中,简单地使用os.Rename
对我来说工作得很好。
进一步阅读:
- rename()是原子的吗?"是也不是。rename()是原子的,假设操作系统没有崩溃...."
- 是一个原子文件重命名(覆盖)可能在Windows上?
*注:我确实想指出,当人们从应用程序的角度谈论原子文件系统文件操作时,他们通常意味着从用户的角度来看操作发生或不发生(日志记录可以帮助)。如果您在原子内存操作的意义上使用原子操作,那么很少有文件系统操作(除了直接I/O [O_DIRECT]一个块在禁用磁盘缓冲的情况下写和读)可以被认为是真正的原子操作。