我正在使用Apache Commons IO:
FileUtils.copyFileToDirectory(srcFile, destDir)
如何让Windows在复制过程中locking目标文件? 如果我使用Windows,则会正确locking文件:
Runtime.getRuntime().exec( "cmd /c copy /Y \"" + srcFile.getCanonicalPath() + "\" \"" + destDir.getCanonicalPath() + "\"").waitFor();
注意:争用不是本地程序,而是外部程序。 该文件正被复制到远程系统。 远程系统在完成复制之前正在处理文件。 由于系统是Windows,正常的副本将locking文件并阻止外部程序访问。
Java本身不支持文件锁定。
如果文件争用来自您的程序,也许您需要在文件副本之上构建额外的同步,以确保并发写入不会互相破坏。 但是,如果争用来自软件外部,那么你可以做的事情就不多了。 您可以尝试将文件写入临时目录,然后重命名该文件,因为重命名或多或少是原子的(取决于文件系统)。
这将有助于有更多的信息,为什么你需要锁定文件的第一位。
这个争论不是在本地的程序中,而是在外部的。 该文件正被复制到远程系统。 远程系统在完成复制之前正在处理文件。 由于系统是Windows,正常的副本将锁定文件并阻止外部程序访问。
在这种情况下,您应该尝试写入临时文件,然后在完全复制文件时对其进行重命名。 文件重命名是原子操作(在一个非联网的文件系统),所以它应该为你工作。
java.nio.channels.FileChannel将允许您使用底层文件系统的本机方法来获取文件上的FileLock,前提是支持此类功能。
这个锁在机器上运行,甚至是非java的。 (实际上,锁是代表特定的JVM实例进行的,所以不适合用于管理进程中多个线程之间的争用,也不适用于同一个JVM中的多个进程)。
这里有很多警告,但是如果你在Windows上工作,这是值得研究的。
从javadoc:
这个文件锁定API旨在直接映射到底层操作系统的本机锁定工具。 因此,无论程序写入的语言如何,文件上的锁应该对所有有权访问该文件的程序都可见。
锁是否实际上阻止另一个程序访问锁定区域的内容是依赖于系统的,因此是未指定的。 某些系统的本机文件锁定功能仅仅是建议性的,这意味着程序必须协作地观察已知的锁定协议以保证数据的完整性。 在其他系统上,本地文件锁定是强制性的,这意味着如果一个程序锁定文件的某个区域,则实际上阻止其他程序以违反该锁定的方式访问该区域。 在其他系统上,本地文件锁是建议性的还是强制性的,可以在每个文件的基础上配置。 为了确保跨平台的一致和正确的行为,强烈建议使用由此API提供的锁,就好像它们是咨询锁一样。
在某些系统上,获取文件区域上的强制锁定可以防止将该区域映射到内存中,反之亦然。 应该为组合锁定和映射的程序做好准备,使这个组合失败。
在某些系统上,关闭通道会释放基础文件上Java虚拟机持有的所有锁,无论锁是通过该通道还是通过在同一文件上打开的另一个通道获取的。 强烈建议在一个程序中,使用一个唯一的通道来获取任何给定文件上的所有锁。
某些网络文件系统只有在锁定区域是页面对齐的时候才允许文件锁定与内存映射文件一起使用,并且是底层硬件页面大小的整数倍。 某些网络文件系统不会在扩展到特定位置(通常为230或231)的区域上实现文件锁定。一般来说,锁定驻留在网络文件系统上的文件时应格外小心。
复制文件时,请务必复制到临时文件名,并在完成写入时重命名文件。 这样,另一个进程永远不会看到损坏的文件。
更好的是,你可以写入* .tmp。 然后检查目标文件是否存在。 将dest文件重命名为* .bak(如果存在)。 最后重命名* .tmp – > dest。