【问题标题】:WatchService fires ENTRY_MODIFY sometimes twice and sometimes onceWatchService 有时会触发 ENTRY_MODIFY 两次,有时会触发一次
【发布时间】:2017-01-02 00:44:16
【问题描述】:

我正在使用来自 Oracle 的 WatchService 示例:

import java.nio.file.*;
import static java.nio.file.StandardWatchEventKinds.*;
import static java.nio.file.LinkOption.*;
import java.nio.file.attribute.*;
import java.io.*;
import java.util.*;

public class WatchDir {

private final WatchService watcher;
private final Map<WatchKey,Path> keys;
private final boolean recursive;
private boolean trace = false;

@SuppressWarnings("unchecked")
static <T> WatchEvent<T> cast(WatchEvent<?> event) {
    return (WatchEvent<T>)event;
}

/**
 * Register the given directory with the WatchService
 */
private void register(Path dir) throws IOException {
    WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
    if (trace) {
        Path prev = keys.get(key);
        if (prev == null) {
            System.out.format("register: %s\n", dir);
        } else {
            if (!dir.equals(prev)) {
                System.out.format("update: %s -> %s\n", prev, dir);
            }
        }
    }
    keys.put(key, dir);
}

/**
 * Register the given directory, and all its sub-directories, with the
 * WatchService.
 */
private void registerAll(final Path start) throws IOException {
    // register directory and sub-directories
    Files.walkFileTree(start, new SimpleFileVisitor<Path>() {
        @Override
        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
                throws IOException
        {
            register(dir);
            return FileVisitResult.CONTINUE;
        }
    });
}

/**
 * Creates a WatchService and registers the given directory
 */
WatchDir(Path dir, boolean recursive) throws IOException {
    this.watcher = FileSystems.getDefault().newWatchService();
    this.keys = new HashMap<WatchKey,Path>();
    this.recursive = recursive;

    if (recursive) {
        System.out.format("Scanning %s ...\n", dir);
        registerAll(dir);
        System.out.println("Done.");
    } else {
        register(dir);
    }

    // enable trace after initial registration
    this.trace = true;
}

/**
 * Process all events for keys queued to the watcher
 */
void processEvents() {
    for (;;) {

        // wait for key to be signalled
        WatchKey key;
        try {
            key = watcher.take();
        } catch (InterruptedException x) {
            return;
        }

        Path dir = keys.get(key);
        if (dir == null) {
            System.err.println("WatchKey not recognized!!");
            continue;
        }

        for (WatchEvent<?> event: key.pollEvents()) {
            WatchEvent.Kind kind = event.kind();

            // TBD - provide example of how OVERFLOW event is handled
            if (kind == OVERFLOW) {
                continue;
            }

            // Context for directory entry event is the file name of entry
            WatchEvent<Path> ev = cast(event);
            Path name = ev.context();
            Path child = dir.resolve(name);

            // print out event
            System.out.format("%s: %s\n", event.kind().name(), child);

            // if directory is created, and watching recursively, then
            // register it and its sub-directories
            if (recursive && (kind == ENTRY_CREATE)) {
                try {
                    if (Files.isDirectory(child, NOFOLLOW_LINKS)) {
                        registerAll(child);
                    }
                } catch (IOException x) {
                    // ignore to keep sample readbale
                }
            }
        }

        // reset key and remove from set if directory no longer accessible
        boolean valid = key.reset();
        if (!valid) {
            keys.remove(key);

            // all directories are inaccessible
            if (keys.isEmpty()) {
                break;
            }
        }
    }
}

static void usage() {
    System.err.println("usage: java WatchDir [-r] dir");
    System.exit(-1);
}

public static void main(String[] args) throws IOException {
    // parse arguments
    if (args.length == 0 || args.length > 2)
        usage();
    boolean recursive = false;
    int dirArg = 0;
    if (args[0].equals("-r")) {
        if (args.length < 2)
            usage();
        recursive = true;
        dirArg++;
    }

    // register directory and process its events
    Path dir = Paths.get(args[dirArg]);
    new WatchDir(dir, recursive).processEvents();
}
}

我正在Windows 7开发一个应用,部署环境是rhel 7.2。起初,在这两个操作系统中,每当我复制一个文件时,它都会触发一个ENTRY_CREATED,然后触发两个ENTRY_MODIFY。第一个ENTRY_MODIFY 在复制开始,第二个ENTRY_MODIFY 在复制结束。所以我能够理解复制过程已经结束。但是,它现在只在rhel 7.2 中触发一个ENTRY_MODIFY。它仍然会在Windows 7 中触发两个ENTRY_MODIFY 事件。

我在stackoverflow 中找到了this。这个问题问为什么两个ENTRY_MODIFY 被解雇了。这不完全是我的问题,但它的答案之一与我的要求存在争议。可悲的是,在这场争论中我的问题没有解决方案。

因为最后没有触发ENTRY_MODIFY,而只是在复制开始时,所以我无法理解复制何时完成。您认为这可能是什么原因?可以修复吗,我怎么理解复制完成了?我不能改变rhel 7.2,但除此之外我很乐意接受。提前致谢。

【问题讨论】:

  • 您好,请查看我的回答here,以了解您的文件何时被复制。 HTH。
  • 感谢您的回复,您的评论我看了很多遍。但是,我不明白获取文件锁将如何帮助我了解复制过程何时结束。能详细解释一下吗?
  • 只要复制过程忙,文件就会保持锁定以供其他进程/线程进行 RW 访问。我的答案中的代码片段试图获得对该文件的锁定(在您通过ENTRY_CREATED 事件知道它的存在之后)。一旦文件不再被复制过程锁定,将立即授予锁定。至此,复制过程完成。
  • 您好,在 processEvents 方法中我检查 ENTRY_CREATE 事件,然后将您的代码块添加到该条件中。但是,它会触发 java.io.FileNotFoundExcepiton :该进程无法访问该文件,因为它正在被另一个进程使用。也许我用错了。您能否在我的示例中添加您的代码块,看看它是否有效。这样我才能接受你的回答。

标签: java rhel watchservice nio2


【解决方案1】:

您可以使用DelayQueue 对事件进行重复数据删除。

【讨论】:

    【解决方案2】:

    我只是检查文件长度是否为零。 这里是一个例子

    for (WatchEvent<?> event : key.pollEvents()) {
        Path fileName = (Path) event.context();
        if("tomcat-users.xml".equals(fileName.toString())) {
            Path tomcatUsersXml = tomcatConf.resolve(fileName);
            if(tomcatUsersXml.toFile().length() > 0) {
                load(tomcatUsersXml);
            }
        } 
    }
    

    【讨论】:

    • 很高兴在 stackoverflow 上找到一个天才 - 我没有运气在另一个线程上找到我喜欢的任何东西,但这很棒if (path.toFile().length() &gt; 0)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-26
    • 1970-01-01
    • 2018-07-21
    • 1970-01-01
    • 2012-01-04
    • 1970-01-01
    相关资源
    最近更新 更多