以原子方式将byte[]写入文件

3
(这是一个假设性问题,因为它非常广泛,并且特定情况下存在解决方法。)
是否可能原子地将byte[]写入文件(如FileOutputStreamFileWriter)?
如果写入失败,则不能接受部分数组被写入。例如,如果数组是1,000,000字节且在500,000字节后磁盘已满,则不应写入任何字节到文件中,或者更改应该以某种方式回滚。即使在写入过程中介质物理断开连接的情况下,也应如此。
假设已知数组的最大大小。

如果磁盘被物理断开连接,就无法截断文件。因此,需要编写一个“XXX.YYY.part”文件,并在成功完成后删除任何旧的XXX.YYY并进行重命名。 - Joop Eggen
1个回答

8

文件的原子写入是不可能的。操作系统不支持它,因此编程语言库也无法实现。

在传统文件系统中,您可以得到的最好的结果是文件的原子重命名;即

  1. write new file into same file system as the old one

  2. use FileDescriptor.sync() to ensure that new file is written

  3. rename the new file over the old one; e.g. using

    java.nio.file.Files.move(Path source, Path target, 
                             CopyOption... options) 
    

    with CopyOptions ATOMIC_MOVE. According to the javadocs, this may not be supported, but if it isn't supported you should get an exception.

但请注意,原子性是在操作系统中实现的,如果操作系统无法提供足够强的保证,那么您就会运气不佳。
(其中一个问题是在硬盘错误发生时可能会发生什么。如果磁盘完全死亡,则原子性无关紧要。但如果操作系统在故障后仍能从磁盘读取数据,则结果可能取决于操作系统修复可能不一致的文件系统的能力。)

为什么要使用Files.move而不是File#renameTo?简单来说,因为前者可能支持原子性操作。 - Eugene
2
使用 moveATOMIC_MOVE,应用程序编写者可以确保移动操作是原子性的,否则会抛出异常。而使用 rename,原子性并未得到明确说明,因此可能会出现重命名失败的情况...非原子性的。 - Stephen C

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接