java 如何判断文件何时“完成”复制到监视目录中?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17933557/
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
How to tell when a File is "Done" copying into a watched Directory?
提问by eric
I'm using the WatchServiceAPI to watch a directory, and getting ENTRY_CREATEevents when a user starts copying a file into the directory. The files I'm working with can be large, though, and I'd like to know when the copy is finished. Is there any built in java API I can use to accomplish this, or am I best off to just keep track of the created files' size and start processing when the size stops growing?
我正在使用WatchServiceAPI 来监视目录,并在用户开始将文件复制到目录中时获取ENTRY_CREATE事件。不过,我正在处理的文件可能很大,我想知道副本何时完成。是否有任何内置的 Java API 可以用来完成此操作,或者我最好只跟踪创建的文件的大小并在大小停止增长时开始处理?
EDIT: Here is my example code:
编辑:这是我的示例代码:
package com.example;
import java.io.File;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
public class Monitor {
public static void main(String[] args) {
try {
String path = args[0];
System.out.println(String.format( "Monitoring %s", path ));
WatchService watcher = FileSystems.getDefault().newWatchService();
Path watchPath = FileSystems.getDefault().getPath(path);
watchPath.register(watcher, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY);
while (true) {
WatchKey key = watcher.take();
for (WatchEvent<?> event: key.pollEvents()) {
Object context = event.context();
System.out.println( String.format( "Event %s, type %s", context, event.kind() ));
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Which Produces this output:
产生这个输出:
Monitoring /Users/ericcobb/Develop/watch
Event .DS_Store, type ENTRY_MODIFY
Event 7795dab5-71b1-4b78-952f-7e15a2f39801-84f3e5daeca9435aa886fbebf7f8bd61_4.mp4, type ENTRY_CREATE
回答by Jeffrey
When an entry is created, you will get an ENTRY_CREATE
event. For every subsequent modification, you will get an ENTRY_MODIFY
event. When copying is completed, you will be notified with an ENTRY_MODIFY
.
创建条目后,您将收到一个ENTRY_CREATE
事件。对于随后的每次修改,您都会收到一个ENTRY_MODIFY
事件。复制完成后,您将收到通知ENTRY_MODIFY
。
回答by Matthias Ronge
- I think that the most common way to accomplish this is to copy the file into a temporary directory on the same partition and then move it to the monitored directory by an atomic move command.
- Perhaps a solution could also be achieved by playing around with the files time stamps
- 我认为最常见的方法是将文件复制到同一分区的临时目录中,然后通过原子移动命令将其移动到受监控的目录。
- 也许也可以通过玩弄文件时间戳来实现解决方案
However both of these solutions need to be realized in the writing application. I think you cannot tell surely from the reading application.
然而,这两种解决方案都需要在写作应用程序中实现。我认为您无法从阅读应用程序中确定。
回答by Gerald Mücke
The only valid option to ensure, no other process is writing to the file anymore is to successfully obtain a Write lock on the file. Although a bit clumsy, you could use FileChanneland FileLockfor that purpose
确保没有其他进程再写入文件的唯一有效选项是成功获得文件的写锁。虽然有点笨拙,但您可以为此目的使用FileChannel和FileLock
try(FileChannel ch = FileChannel.open(p, StandardOpenOption.WRITE);
FileLock lock = ch.tryLock()){
if(lock == null) {
//no lock, other process is still writing
} else {
//you got a lock, other process is done writing
}
} catch (IOException e) {
//something else went wrong
}
You could as well obtain a lock using ch.lock()
which is a blocking call. But since ENTRY_MODIFY events are continously generated when the file is being written to, you can as well use tryLock and wait for the next event.
您也可以使用ch.lock()
阻塞调用获取锁。但是由于 ENTRY_MODIFY 事件在写入文件时会不断生成,因此您也可以使用 tryLock 并等待下一个事件。
回答by eric
This is the library that we use today:
这是我们今天使用的库:
https://github.com/levelsbeyond/jpoller
https://github.com/levelsbeyond/jpoller
It's a fork of an open-source project that the original author no longer maintains. We've fixed a few bugs in it, and today use it in production.
它是原作者不再维护的开源项目的一个分支。我们已经修复了其中的一些错误,今天在生产中使用它。
It works by checking the size of files in a directory, and considers the file done (ready for processing) once the file size stops growing for a period of time.
它的工作原理是检查目录中文件的大小,并在文件大小停止增长一段时间后认为文件已完成(已准备好进行处理)。
回答by Victor Grazi
If you have the ability to control the file writes, you can write to a temp file, then rename it to the target. That should generate a single ENTRY_MODIFY.
如果您有能力控制文件写入,则可以写入临时文件,然后将其重命名为目标。这应该生成一个 ENTRY_MODIFY。
Something like:
就像是:
Path tempFile = Files.createTempFile("tmp", "tmp");
writeSomeContents(tempFile);
Path target = Paths.get(targetFilename);
Files.move(tempFile, target);
I recommend waiting a few MS after receiving the notification, to wait for the move to complete.
我建议在收到通知后等待几个MS,等待移动完成。
回答by Matthias Ronge
Maybe you can tell by trying to acquire write access to the file, but this depends on two factors and requires research:
也许您可以通过尝试获得对文件的写访问权来判断,但这取决于两个因素并且需要研究:
- The writing application must acquire exclusive write permission to the file and mustn't close the file before it is in fact complete.
- It must be possible to test for this from Java. I would give it a try whether opening the file as FileChannelfor WRITE access throws an exception if the file is still locked for writing by another program. Unluckily, the Javadoc doesn't go into detail about this.
- 写入应用程序必须获得对文件的独占写入权限,并且在文件实际上完成之前不得关闭文件。
- 必须可以从 Java 对此进行测试。如果文件仍被锁定以供另一个程序写入,我会尝试将文件作为 FileChannel 打开以进行 WRITE 访问是否会引发异常。不幸的是,Javadoc 没有详细说明这一点。
回答by Gyuyeol
File file = child.toAbsolutePath().toFile();
if(file.isFile() && file.isWrite())
{
}
maybe this would be the way to find out what you want but not in the while statement.
也许这将是找出您想要的但不是在 while 语句中的方法。
It will work when you really access to file.
当您真正访问文件时,它将起作用。