gpt4 book ai didi

java - 如何确保文件写入失败时的文件完整性?

转载 作者:塔克拉玛干 更新时间:2023-11-02 20:20:32 25 4
gpt4 key购买 nike

跟进:How to safely update a file that has many readers and one writer?

在我之前的问题中,我发现您可以使用 FileChannel 的锁来确保读写顺序。

但是,如果编写器在写入过程中失败(比如 JVM 崩溃),您将如何处理这种情况?这个基本算法看起来像,

WRITER:
lock file
write file
release file

READER:
lock file
read file
release file

如果 JVM 在 write file 期间崩溃,肯定会释放锁,但现在我有一个不完整的文件。我想要完整的东西总是可读的。要么是旧内容,要么是新内容,不能介于两者之间。

我的第一个策略是写入一个临时文件,然后将内容复制到“实时”文件中(同时确保良好的锁定)。算法是,

WRITER:
lock temp file
write temp file
lock file
copy temp to file
release file
release temp
delete temp

READER:
lock file
read file
release file

一个好处是 delete temp 不会删除临时文件,如果它已经被另一个作者锁定的话。

但是如果 JVM 在copy temp to file 期间崩溃,该算法将无法处理。所以我添加了一个copying标志,

WRITER:
lock temp file
write temp file
lock file
create copying flag
copy temp to file
delete copying flag
release file
release temp
delete temp

READER:
lock file
if copying flag exists
copy temp to file
delete copying flag
delete temp
end
read file
release file

不会有两件事访问复制文件,因为它受到文件锁的保护。

现在,这是这样做的方法吗?确保非常简单的事情似乎很复杂。是否有一些 Java 库可以帮我处理这个问题?

编辑

好吧,我设法在第三次尝试中犯了一个错误。读取器在 copy temp to file 时不会锁定 temp。简单地锁定临时文件也不是一个简单的修复!这将导致作者和读者以不同的顺序获取锁,并可能导致死锁。这一直在变得越来越复杂。这是我的第四次尝试,

WRITER:
lock file
write temp file
create copying flag
copy temp to file
delete copying flag
delete temp
release file

READER:
lock file
if copying flag exists
copy temp to file
delete copying flag
delete temp
end
read file
release file

这次临时文件由主锁保护,所以它甚至不需要自己的锁。

编辑 2

当我说 JVM 崩溃时,我实际上是说电源断电了,而您没有 UPS。

编辑 3

我还是犯了另一个错误。您不应该锁定正在写入或读取的文件。这会导致问题,因为除非在 Java 中使用 RandomAccessFile,否则无法同时获得读写锁,而 Java 不实现输入/输出流。

您要做的只是锁定一个保护您正在读取或写入的文件的锁定文件。这是更新后的算法:

WRITER:
lock
write temp file
create copying flag
copy temp to file
delete copying flag
delete temp
release

READER:
lock
if copying flag exists
copy temp to file
delete copying flag
delete temp
end
read file
release

锁定和释放保护文件、临时文件和复制标志。唯一的问题是现在读者锁不能共享,但它永远不可能是真的。读者总是有机会修改文件,因此一开始就设置共享锁是错误的。

最佳答案

尽管没有万无一失、跨操作系统、跨文件系统的解决方案,“写入唯一的临时文件并重命名”策略仍然是您的最佳选择。大多数平台/文件系统都试图使文件重命名(有效地)原子化。请注意,您要使用一个+单独的+锁定文件进行锁定。

因此,假设您要更新“myfile.txt”:

  • 锁定“myfile.txt.lck”(这是一个单独的空文件)
  • 将更改写入唯一的临时文件,例如“myfile.txt.13424.tmp”(使用 File.createTempFile())
  • 为了额外的保护,但可能会更慢,在继续之前 fsync 临时文件 (FileChannel.force(true))。
  • 将“myfile.txt.13424.tmp”重命名为“myfile.txt”
  • 解锁“myfile.txt.lck”

在某些平台(windows)上,由于文件操作的限制,你需要做更多的舞蹈(你可以在重命名之前将“myfile.txt”移动到“myfile.txt.old”,并使用“.old”阅读时需要恢复的文件)。

关于java - 如何确保文件写入失败时的文件完整性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/462696/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com