原子文件写操作(跨平台)

32 投票
7 回答
17611 浏览
提问于 2025-04-15 17:55

我该如何实现一个原子文件写入操作?这个文件会由一个Java服务写入,然后被Python脚本读取。
需要说明的是,读取的次数远远超过写入。但写入是批量进行的,而且通常需要较长时间。文件的大小可以达到几兆字节。

目前我的做法是:

  • 先把文件内容写入一个临时文件,放在同一个目录下
  • 删除旧文件
  • 把临时文件重命名为旧文件的名字。

这样做对吗?我该如何避免在旧文件被删除但新文件还没重命名的情况下出现问题?

这些编程语言(Python和Java)有没有提供一些机制来锁定文件,避免这种情况发生?

7 个回答

3

这是一个经典的生产者/消费者问题。你可以通过重命名文件来解决这个问题,在POSIX系统上,这个操作是原子的,也就是说它要么完全成功,要么完全失败,不会出现中间状态。

7

在POSIX平台上,可以省略第3步(删除旧文件)。在POSIX系统中,文件系统内的重命名操作是保证原子性的,也就是说,重命名一个已经存在的文件会直接替换掉它,而这个过程是瞬间完成的。

14

据我所知,没有。

原因是,要实现这样的原子操作,操作系统需要支持一种叫做事务文件系统的东西。但目前主流的操作系统都没有提供这种事务文件系统。

补充说明 - 至少在符合POSIX标准的系统上,我之前说错了。POSIX中的rename系统调用在目标名称已经存在的情况下,会执行一个原子替换……正如@janneb所指出的。这应该足以让提问者的操作以原子方式进行。

不过,事实是Java中的File.renameTo()方法并不保证是原子的,所以它不能作为跨平台解决方案来解决提问者的问题。

补充说明 2 - 从Java 7开始,你可以使用java.nio.file.Files.move(Path source, Path target, CopyOption... options),并结合ATOMIC_MOVE选项。如果操作系统或文件系统不支持这个功能,你会收到一个异常提示。

撰写回答