27

我正在使用WatchService API 来监视目录,并在用户开始将文件复制到目录中时获取ENTRY_CREATE事件。不过,我正在使用的文件可能很大,我想知道副本何时完成。是否有任何内置的 java API 可以用来完成此操作,或者我最好只跟踪创建的文件的大小并在大小停止增长时开始处理?

编辑:这是我的示例代码:

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();
        }
    }
}

产生此输出:

Monitoring /Users/ericcobb/Develop/watch
Event .DS_Store, type ENTRY_MODIFY
Event 7795dab5-71b1-4b78-952f-7e15a2f39801-84f3e5daeca9435aa886fbebf7f8bd61_4.mp4, type ENTRY_CREATE
4

7 回答 7

10

创建条目后,您将获得一个ENTRY_CREATE事件。对于每个后续修改,您将获得一个ENTRY_MODIFY事件。复制完成后,您将收到通知ENTRY_MODIFY

于 2013-07-29T20:35:55.453 回答
6

确保不再有其他进程写入文件的唯一有效选项是成功获得文件上的写入锁。虽然有点笨拙,但您可以为此目的使用FileChannelFileLock

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
 }

ch.lock()您也可以使用阻塞调用获取锁。但是由于在写入文件时会不断生成 ENTRY_MODIFY 事件,因此您也可以使用 tryLock 并等待下一个事件。

于 2017-05-11T18:25:14.080 回答
3
  • 我认为实现这一点的最常见方法是将文件复制到同一分区上的临时目录中,然后通过原子移动命令将其移动到受监控的目录中。
  • 也许也可以通过玩弄文件时间戳来实现解决方案

然而,这两种解决方案都需要在写作应用程序中实现。我认为您无法从阅读应用程序中确定。

于 2014-07-15T13:54:25.043 回答
2

这是我们今天使用的库:

https://github.com/levelsbeyond/jpoller

它是原作者不再维护的开源项目的一个分支。我们已经修复了其中的一些错误,今天在生产中使用它。

它通过检查目录中文件的大小来工作,并在文件大小停止增长一段时间后认为文件已完成(准备好处理)。

于 2014-07-16T14:53:31.323 回答
0

也许您可以通过尝试获取对文件的写入权限来判断,但这取决于两个因素并且需要研究:

  1. 写入应用程序必须获得对文件的独占写入权限,并且在文件实际上完成之前不得关闭文件。
  2. 必须可以从 Java 中对此进行测试。如果文件仍被另一个程序锁定以供写入,我会尝试将文件作为 FileChannel 打开以进行 WRITE 访问是否会引发异常。不幸的是,Javadoc 没有对此进行详细介绍。
于 2014-07-16T06:35:44.167 回答
0

如果您有能力控制文件写入,则可以写入临时文件,然后将其重命名为目标。那应该生成一个 ENTRY_MODIFY。

就像是:

Path tempFile = Files.createTempFile("tmp", "tmp");
writeSomeContents(tempFile);
Path target = Paths.get(targetFilename);
Files.move(tempFile, target);

我建议在收到通知后等待几个 MS,等待移动完成。

于 2019-03-17T23:32:28.583 回答
-1
File file = child.toAbsolutePath().toFile();
if(file.isFile() && file.isWrite())
{
}

也许这将是找出你想要的东西的方法,但不是在 while 语句中。

当您真正访问文件时,它将起作用。

于 2015-03-17T13:33:17.267 回答