【问题标题】:Atomic file write operations (cross platform)原子文件写入操作(跨平台)
【发布时间】:2011-01-04 04:32:48
【问题描述】:

如何构建原子文件写入操作?该文件将由 Java 服务编写并由 python 脚本读取。
为了记录,读取远远大于写入。但是写入是分批进行的,而且往往很长。文件大小为兆字节。

现在我的做法是:

  • 将文件内容写入临时文件 同一目录
  • 删除旧文件
  • 将临时文件重命名为旧文件名。

这是正确的方法吗?如何避免旧文件被删除但新文件名尚未重命名的情况?

这些编程语言(python 和 java)是否提供结构来锁定和避免这种情况?

【问题讨论】:

标签: java python file file-io


【解决方案1】:

AFAIK 没有。

原因是,要使这样的原子操作成为可能,必须以事务文件系统的形式提供操作系统支持。并且没有一个主流操作系统提供事务文件系统。

EDIT - 至少对于 POSIX 兼容的系统,我错了。如果具有目标名称的文件已经存在,则 POSIX rename 系统调用执行原子替换......正如@janneb 所指出的那样。这应该足以原子地执行 OP 的操作。

然而,事实仍然是 Java File.renameTo() 方法明确保证是原子的,因此它没有为 OP 的问题提供跨平台解决方案。

EDIT 2 - 在 Java 7 中,您可以将 java.nio.file.Files.move(Path source, Path target, CopyOption... options) 与 copyOptions 和 ATOMIC_MOVE 一起使用。如果不支持(操作系统/文件系统),你应该得到一个例外。

【讨论】:

  • +1:啊,那些讨厌的操作系统差异阻碍了“跨平台”解决方案。
  • 真正的答案是应该使用文件锁。
  • “而且没有一个主流操作系统提供事务文件系统。”什么?? NTFS 长期以来一直支持事务。 msdn.microsoft.com/en-us/magazine/cc163388.aspx
  • @unixman83 您可以在向其中写入数据时锁定新文件,但是如何锁定目录以进行原子交换? :)
  • @Ark-kun - 我不知道。但是,它实际上并没有帮助,因为大多数文件系统都没有该功能,并且它没有通过标准 Java API 公开。
【解决方案2】:

至少在 POSIX 平台上,省略第 3 步(删除旧文件)。在 POSIX 中,文件系统中的重命名保证是原子的,并且在现有文件之上重命名会原子地替换它。

【讨论】:

    【解决方案3】:

    这是一个典型的生产者/消费者问题。您应该能够通过使用文件重命名来解决这个问题,这在 POSIX 系统上是原子的。

    【讨论】:

      【解决方案4】:

      在 Linux、Solaris、Unix 中,这很容易。只需使用程序中的rename() 或mv。这些文件需要在同一个文件系统上。

      在 Windows 上,如果您可以控制这两个程序,这是可能的。 LockFileEx。对于读取,请在锁定文件上打开 shared lock。对于写入,请在锁定文件上打开 exclusive lock。锁定在 Windows 中很奇怪,因此我建议为此使用单独的 锁定文件

      【讨论】:

        【解决方案5】:

        您可以尝试使用额外的文件作为锁,但我不确定这是否可行。 (这会迫使您在 java 和 python 双方都创建锁检查和重试逻辑)

        另一种解决方案可能是根本不创建文件,也许您可​​以让您的 java 进程在端口上侦听并从那里而不是从文件中提供数据?

        【讨论】:

          【解决方案6】:

          让 python 脚本请求服务的权限。当服务正在写入时,它会锁定文件。如果锁存在,服务将拒绝 python 请求。

          【讨论】:

            【解决方案7】:

            【讨论】:

            • 是的...但这不允许您进行原子文件替换。
            • 你说的不完全正确。使用此 API,您可以创建“.lock”文件并将其用作信号量。用例:如果文件被锁定 - python 等到它被解锁,然后在读取解锁文件后开始读取(并锁定文件)。当服务需要写入数据时 - 检查文件是否被锁定,等到它被解锁,锁定它,写入数据,解锁它。
            • 无论如何,这实际上是一个仅限链接的答案,并且该链接没有解释如何解决 OP 的问题。按照今天的标准,这是一个低质量的答案。
            • 文档中的重要部分:“锁是否真正阻止另一个程序访问锁定区域的内容取决于系统,因此未指定。”
            • @St.Shadow,锁可以防止您的程序的另一个正确运行的副本同时更改内容,但这并不意味着操作系统崩溃,或者JVM 错误等不会使您的文件部分写入或损坏(适当的原子创建和重命名工作流程会这样做)。
            猜你喜欢
            • 2011-02-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-05-05
            • 2012-08-09
            • 1970-01-01
            • 2015-11-29
            相关资源
            最近更新 更多