如何在Windows上创build,然后primefaces重命名文件在Java?

我正在尝试使用Java在Windows正确执行“写入临时文件并重命名”。

如何在Java中自动重命名文件,即使dest文件已经存在? build议重命名文件是“primefaces操作”(无论“primefaces”实际上是什么意思)。 https://stackoverflow.com/a/20570968/65458build议编写tmp文件,重命名是跨平台的,并确保最终文件不存在或可以由其他进程处理。

所以我试图实际执行这种方法。 以下是我的尝试总结。 对于实际的问题 – 跳到底部。

写方法

我尝试了各种写入和重命名文件的方法( contentcharset分别是StringCharset ):

使用java.nio.file.Files

 Files.copy(new ByteArrayInputStream(content.getBytes(charset)), tmpFile); Files.move(tmpFile, finalFile, StandardCopyOption.ATOMIC_MOVE); 

使用番石榴(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(); 

读取方法

现在假定另一个线程(线程,因为我在testing中,实际上它可能是另一个进程)正在执行以下版本的代码之一:

通用function:

 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, 0, n, charset)); } } return sb.toString(); 

结果

如果我阅读使用“ java.nio.file.Files方法”,一切工作正常。

如果我在Linux上运行这个代码(这个问题的范围之外,我知道),一切工作正常。

但是,如果我实现阅读番石榴或FileInputStream ,然后可能高于0.5%(0.005)的testing失败

java.io.FileNotFoundException:进程无法访问该文件,因为正在被另一个进程使用

(由我自己翻译的消息导致我的窗口不是英文;引用“另一个进程”是误导性的,因为即使这是相同的过程,Windows也是正常的,我用明确的阻塞来validation。

如何在Windows上使用Java实现创build – 然后重命名,以便最终文件以primefaces方式出现,即不存在或可以被读取?

由于我对进程有控制权,所以我不能假设任何特定的阅读方法,甚至不能使用Java。 因此该解决scheme应该与上面列出的所有读取方法一起工

Solutions Collecting From Web of "如何在Windows上创build,然后primefaces重命名文件在Java?"

这似乎只是Windows / NTFS的行为。

而且,使用旧的IO和NIO的读取之间的行为差​​异可能是因为它们使用不同的Windows API。

维基百科对文件锁定说

对于在Windows中使用文件读/写API的应用程序,在Windows中执行的文件系统强制执行字节范围锁(也称为强制锁)。 对于在Windows中使用文件映射API的应用程序,不执行字节范围锁定(也称为建议锁定)。

虽然维基百科不是Windows的文档,但这仍然有一些亮点。

(我把这个答案只是为了让其他人也不用这样写,真正的答案,参考文档或报告的错误,非常感谢。)

在JDK中有java.io.File.renameTo()函数的bug报告,它在Windows上不是原子性的,已经关闭,不会修复: http : //bugs.java.com/bugdatabase/view_bug.do?bug_id = 4017593 。 所以可能没有一个干净的方法来解决你的问题。