windows 使用 Commons IO 复制时锁定文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/473379/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Locking a file while copying using Commons IO
提问by Joshua
I am using the Apache Commons IO:
我正在使用 Apache Commons IO:
FileUtils.copyFileToDirectory(srcFile, destDir)
How do I make Windows lock the destination file during copy? Windows locks the file correctly if I use:
如何让 Windows 在复制过程中锁定目标文件?如果我使用,Windows 会正确锁定文件:
Runtime.getRuntime().exec(
"cmd /c copy /Y \"" + srcFile.getCanonicalPath() + "\" \""
+ destDir.getCanonicalPath() + "\"").waitFor();
Notes: The contention is not with the local program, but an external one. The file is being copied to a remote system. The remote system is processing the file before it completes the copy. Because the systems are Windows, the normal copy locks the file and blocks the external program from access.
注:争用的不是本地程序,而是外部程序。正在将文件复制到远程系统。远程系统在完成复制之前正在处理文件。因为系统是 Windows,所以普通副本会锁定文件并阻止外部程序访问。
采纳答案by Kevin
Java doesn't natively support file locking.
Java 本身不支持文件锁定。
If contention for the file is coming from within your program, perhaps you need to build additional synchronization on top of the file copy to make sure concurrent writes don't clobber one another. However, if the contention is coming from somewhere external to your software then there isn't much you can do. You can try writing the file to a temporary directory and then renaming it since the rename is more or less atomic (depending on the filesystem).
如果文件争用来自您的程序,您可能需要在文件副本之上构建额外的同步,以确保并发写入不会相互破坏。但是,如果争用来自软件外部的某个地方,那么您无能为力。您可以尝试将文件写入临时目录,然后重命名它,因为重命名或多或少是原子的(取决于文件系统)。
It would help to have more information on why you need to lock the file in the first place.
了解更多有关为什么需要首先锁定文件的信息会有所帮助。
The contention is not with the local program, but an external one. The file is being copied to a remote system. The remote system is processing the file before it completes the copy. Because the systems are Windows, the normal copy locks the file and blocks the external program from access.
争用不是本地程序,而是外部程序。正在将文件复制到远程系统。远程系统在完成复制之前正在处理文件。因为系统是 Windows,所以普通副本会锁定文件并阻止外部程序访问。
In that case, you should try writing to a temporary file and then renaming it when the file is fully copied. File renames are atomic operations (on a non networked filesystem) so it should work for you.
在这种情况下,您应该尝试写入临时文件,然后在文件完全复制后重命名它。文件重命名是原子操作(在非网络文件系统上),所以它应该适合你。
回答by Bill Michell
java.nio.channels.FileChannelwill allow you to acquire a FileLockon a file, using a method native to the underlying file system, assuming such functionality is supported.
java.nio.channels.FileChannel将允许您使用底层文件系统的本地方法获取文件上的FileLock,假设支持此类功能。
This lock operates across processes on the machine, even non-java ones. (In fact, the lock is held on behalf of the specific JVM instance, so is not suitable for managing contention between multiple threads in a process, or multiple processes in the same JVM).
此锁可跨机器上的进程运行,即使是非 Java 进程。(实际上,锁是代表特定的JVM实例持有的,所以不适合管理一个进程中多个线程之间的争用,或者同一个JVM中的多个进程)。
There are lots of caveats here, but it is worth investigating if you are working on Windows.
这里有很多注意事项,但如果您使用的是 Windows,则值得研究一下。
From the javadoc:
从javadoc:
This file-locking API is intended to map directly to the native locking facility of the underlying operating system. Thus the locks held on a file should be visible to all programs that have access to the file, regardless of the language in which those programs are written.
Whether or not a lock actually prevents another program from accessing the content of the locked region is system-dependent and therefore unspecified. The native file-locking facilities of some systems are merely advisory, meaning that programs must cooperatively observe a known locking protocol in order to guarantee data integrity. On other systems native file locks are mandatory, meaning that if one program locks a region of a file then other programs are actually prevented from accessing that region in a way that would violate the lock. On yet other systems, whether native file locks are advisory or mandatory is configurable on a per-file basis. To ensure consistent and correct behavior across platforms, it is strongly recommended that the locks provided by this API be used as if they were advisory locks.
On some systems, acquiring a mandatory lock on a region of a file prevents that region from being mapped into memory, and vice versa. Programs that combine locking and mapping should be prepared for this combination to fail.
On some systems, closing a channel releases all locks held by the Java virtual machine on the underlying file regardless of whether the locks were acquired via that channel or via another channel open on the same file. It is strongly recommended that, within a program, a unique channel be used to acquire all locks on any given file.
Some network filesystems permit file locking to be used with memory-mapped files only when the locked regions are page-aligned and a whole multiple of the underlying hardware's page size. Some network filesystems do not implement file locks on regions that extend past a certain position, often 230 or 231. In general, great care should be taken when locking files that reside on network filesystems.`
此文件锁定 API 旨在直接映射到底层操作系统的本机锁定设施。因此,文件上的锁应该对所有有权访问该文件的程序可见,而不管这些程序是用什么语言编写的。
锁是否真正阻止另一个程序访问锁定区域的内容取决于系统,因此未指定。某些系统的本地文件锁定功能只是建议性的,这意味着程序必须协同遵守已知的锁定协议以保证数据完整性。在其他系统上,本地文件锁是强制性的,这意味着如果一个程序锁定了文件的某个区域,那么实际上会阻止其他程序以违反锁的方式访问该区域。在其他系统上,本机文件锁是建议性的还是强制性的,可以在每个文件的基础上进行配置。为了确保跨平台的行为一致和正确,强烈建议将此 API 提供的锁用作建议锁。
在某些系统上,获取对文件区域的强制锁定会阻止该区域被映射到内存中,反之亦然。结合锁定和映射的程序应该为这种结合失败做好准备。
在某些系统上,关闭通道会释放 Java 虚拟机在底层文件上持有的所有锁,无论这些锁是通过该通道还是通过在同一文件上打开的另一个通道获取的。强烈建议在程序中使用唯一的通道来获取任何给定文件的所有锁。
某些网络文件系统仅在锁定区域是页面对齐的并且是底层硬件页面大小的整数倍时才允许将文件锁定与内存映射文件一起使用。一些网络文件系统不会在超过某个位置(通常是 230 或 231)的区域上实现文件锁定。通常,锁定驻留在网络文件系统上的文件时应格外小心。
回答by Aaron Digulla
When copying files, always copy to a temporary filename and rename the file when you are done writing. This way, another process can never see a corrupt file.
复制文件时,请始终复制到临时文件名,并在完成写入后重命名文件。这样,另一个进程就永远无法看到损坏的文件。
Even better, you can write to *.tmp. Then check if the destination file exists. Rename the dest file to *.bak if it exists. Lastly rename *.tmp -> dest.
更好的是,您可以写入 *.tmp。然后检查目标文件是否存在。将 dest 文件重命名为 *.bak(如果存在)。最后重命名 *.tmp -> dest。