如何在Windows上用Java创建 – 然后 – 原子重命名文件?
我正在尝试在
Windows上使用
Java正确实现“写临时文件并重命名”.
How to atomically rename a file in Java,even if the dest file already exists?建议重命名文件是“原子操作”(无论“原子”实际上是什么意思). 所以我试着实际实现这种方法.以下是我的尝试摘要.对于实际问题 – 跳到底部. 写方法 我尝试了各种编写和重命名文件的方法(内容和字符集分别是String和Charset): 使用java.nio.file.Files: Files.copy(new ByteArrayInputStream(content.getBytes(charset)),tmpFile); Files.move(tmpFile,finalFile,StandardCopyOption.ATOMIC_MOVE); 使用Guava(14)和java.io.File: com.google.common.io.Files.write(content,tmpFile,charset); tmpFile.renameTo(finalFile); 或者甚至更模糊的方法: try (OutputStream os = new FileOutputStream(tmpFile); Writer writer = new OutputStreamWriter(os,charset)) { writer.write(content); } Runtime.getRuntime().exec( new String[] { "cmd.exe","/C","move " + tmpFile + " " + finalFile }).waitFor(); 阅读方法 现在假设另一个线程(线程因为我在测试中,在现实生活中它可能是另一个进程)正在执行以下版本的代码之一: 具有共同功能: void waitUntilExists() throws InterruptedException { while (!java.nio.file.Files.exists(finalFile)) { NANOSECONDS.sleep(1); } } 使用java.nio.file.Files: waitUntilExists(); return new String(Files.readAllBytes(finalFile),charset); 使用番石榴(14): waitUntilExists(); return new String(com.google.common.io.Files.toByteArray(finalFile.toFile()),charset); 或者甚至更模糊的方法: waitUntilExists(); StringBuilder sb = new StringBuilder(); try (InputStream is = new FileInputStream(finalFile.toFile())) { byte[] buf = new byte[8192]; int n; while ((n = is.read(buf)) > 0) { sb.append(new String(buf,n,charset)); } } return sb.toString(); 结果 如果我使用“java.nio.file.Files方法”阅读,一切正常. 如果我在Linux上运行此代码(超出此问题的范围,我知道),一切正常. 但是,如果我使用Guava或FileInputStream实现读取,那么可能性高于0.5%(0.005),测试失败
(由我自己翻译的消息导致我的窗口不是英文;提到“另一个进程”是误导性的,因为即使这是相同的过程,Windows也是正常的,我用明确的阻止验证了.) 题 如何在Windows上使用Java实现create-then-rename,以便最终文件以原子方式显示,即要么不存在,要么可以读取? 因为我对进程的控制比拾取文件所控制的,我不能假设使用任何特定的读取方法,或者甚至它们都是Java.因此,该解决方案应适用于上面列出的所有读取方法.
这似乎只是Windows / NTFS的行为方式.
此外,使用旧IO和NIO的读取之间的行为差??异可能是因为它们使用不同的Windows API. Wikipedia on File locking说
虽然维基百科不是Windows的文档,但这仍然有所启发. (我只是把这个答案放在一起,以便其他人也不必写这个.真正的答案,参考文档或报告的错误,非常感谢.) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |