Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/blackberry/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何保证Java中文件的原子移动或异常?_Java_Multithreading_Atomic_Java.nio.file - Fatal编程技术网

如何保证Java中文件的原子移动或异常?

如何保证Java中文件的原子移动或异常?,java,multithreading,atomic,java.nio.file,Java,Multithreading,Atomic,Java.nio.file,在我的一个项目中,我对一个JRE中的一个文件具有并发写访问权,并希望通过首先写入临时文件,然后使用原子移动将临时文件移动到目标来处理该问题。我不关心写访问的顺序,我只需要保证在任何给定的时间单个文件都是可用的。我已经知道Files.move之类的东西,我的问题是我至少看过该方法的一个实现,它引起了一些关于实现是否真的保证原子移动的怀疑。请查看以下代码: 问题在于,并非所有情况下都会考虑原子移动选项,但源路径和目标路径的位置才是最重要的。这不是我想要的,也不是我理解文档的方式: 如果移动不能作为

在我的一个项目中,我对一个JRE中的一个文件具有并发写访问权,并希望通过首先写入临时文件,然后使用原子移动将临时文件移动到目标来处理该问题。我不关心写访问的顺序,我只需要保证在任何给定的时间单个文件都是可用的。我已经知道Files.move之类的东西,我的问题是我至少看过该方法的一个实现,它引起了一些关于实现是否真的保证原子移动的怀疑。请查看以下代码:

问题在于,并非所有情况下都会考虑原子移动选项,但源路径和目标路径的位置才是最重要的。这不是我想要的,也不是我理解文档的方式:

如果移动不能作为原子文件系统操作执行,则 抛出AtomicMoveNotSupportedException。例如,当目标 位置位于不同的文件存储上,需要复制该文件或将其作为目标 位置与此对象的其他提供程序关联

上述代码显然违反了该文档,因为它退回到拷贝删除策略,而根本不识别原子移动。在我的例子中,一个例外是完全可以的,因为有了这个例外,我们服务的宿主可以改变他的设置,只使用一个支持原子移动的文件系统,因为这是我们在系统需求中所期望的。我不想处理的是,由于实现使用了拷贝删除策略,可能会导致目标文件中的数据损坏,所以会出现无声的失败。因此,据我所知,依赖Files.move进行原子操作是不安全的,因为如果不支持这些操作,它并不总是失败,但实现可能会退回到拷贝删除策略


这样的行为是实现中的一个bug,需要归档,还是文档允许这样的行为,而我的理解是错误的?如果我现在已经知道有人在那里使用这种可能被破坏的实现,这有什么区别吗?在这种情况下,我需要自己同步写访问…

标准Java库并不提供在所有情况下执行原子移动的方法

不保证原子移动。您可以将
ATOMIC\u MOVE
作为一个选项传递,但如果移动不能作为一个原子操作执行,则会抛出
AtomicMoveNotSupportedException
(当目标位置位于不同的文件存储区上时,会出现这种情况,需要复制文件)


如果你真的需要,你必须自己实现它。一种解决方案是捕获
AtomicMoveNotSupportedException
,然后执行此操作:尝试在不使用
AtomicMove
选项的情况下移动文件,但如果在复制过程中发生错误,则捕获异常并删除目标。

您看到的位置不正确。当文件系统提供程序不同时,该操作将被委派给
moveToForeignTarget
,正如您在发布的代码片段中看到的那样。但是,方法
moveToForeignTarget
将使用方法
convertMoveToCopyOptions
(注意发音名称…)获取翻译操作所需的复制选项。如果遇到
原子移动
选项,则
convertMoveToCopyOptions
将抛出一个
原子移动不支持异常
,因为无法将该移动选项转换为有效的复制选项


因此,没有理由担心,一般来说,建议避免看到不到十行的代码(特别是在没有尝试过一次测试的情况下)而仓促下结论。

对不起,但你没有抓住要点:我发布的OpenJDK代码明确指出,在任何情况下都不会抛出AtomicMoveNotSupportedException,这就是问题所在。我完全可以忍受这样一个例外,但如果它悄悄地转变为一种退后策略,我就不能。我不知道实现在做什么,我只有官方的API文档,发布的实现违反了这一点。至少这是我的理解…我不会使用违反官方文档的实现。。。在这种特殊情况下,您可以执行导致文件复制的相同检查:检查文件系统提供程序,如果它们不同,请按照
AtomicMoveNotSupportedException
案例中的操作。好的,没有想到最简单的选项,所以现在应该使用一个围绕Files.move的薄型包装器。但是OpenJDK实现是否是一个值得归档的文档缺陷?这看起来太小(认为他们不会关注),但如果是在javadoc中,它应该是这样工作的,所以在我看来,它是值得归档的。测试当然不能保证一般情况下的任何东西,我肯定不会仓促下结论,但我必须承认,我没有意识到对“convertMoveToCopyOptions”的调用,即使我不止一次看过实现。谢谢你的提示@Thorsten Schöning:测试不是最后一句话,但是使用两个不同文件系统的单个测试将推翻从未抛出异常的假设,并显示抛出异常的位置。因此,bug报告通常会添加一个可以重现bug的示例代码。没关系,这样的事情总会发生,与其盲目地相信,不如去问…
1342        FileSystemProvider provider = provider(source);
1343        if (provider(target) == provider) {
1344            // same provider
1345            provider.move(source, target, options);
1346        } else {
1347            // different providers
1348            CopyMoveHelper.moveToForeignTarget(source, target, options);
1349        }