Java 7 WatchService - Ignoring multiple occurrences of the same event

后端 未结 14 634
情歌与酒
情歌与酒 2020-12-05 02:21

The javadoc for StandardWatchEventKinds.ENTRY_MODIFY says:

Directory entry modified. When a directory is registered for this event the

14条回答
  •  暗喜
    暗喜 (楼主)
    2020-12-05 02:35

    If you use RxJava you can use the operator throttleLast. In the example below only the last event in 1000 milliseconds is emitted for each file in the watched directory.

    public class FileUtils {
        private static final long EVENT_DELAY = 1000L;
    
        public static Observable watch(Path directory, String glob) {
            return Observable.create(subscriber -> {
                final PathMatcher matcher = directory.getFileSystem().getPathMatcher("glob:" + glob);
    
                WatchService watcher = FileSystems.getDefault().newWatchService();
                subscriber.setCancellable(watcher::close);
    
                try {
                    directory.register(watcher,
                            ENTRY_CREATE,
                            ENTRY_DELETE,
                            ENTRY_MODIFY);
                } catch (IOException e) {
                    subscriber.onError(e);
                    return;
                }
    
                while (!subscriber.isDisposed()) {
                    WatchKey key;
                    try {
                        key = watcher.take();
                    } catch (InterruptedException e) {
                        if (subscriber.isDisposed())
                            subscriber.onComplete();
                        else
                            subscriber.onError(e);
                        return;
                    }
    
                    for (WatchEvent event : key.pollEvents()) {
                        WatchEvent.Kind kind = event.kind();
    
                        if (kind != OVERFLOW) {
                            WatchEvent ev = (WatchEvent) event;
                            Path child = directory.resolve(ev.context());
    
                            if (matcher.matches(child.getFileName()))
                                subscriber.onNext(new FileWatchEvent(kindToType(kind), child));
                        }
                    }
    
                    if (!key.reset()) {
                        subscriber.onError(new IOException("Invalid key"));
                        return;
                    }
                }
            }).groupBy(FileWatchEvent::getPath).flatMap(o -> o.throttleLast(EVENT_DELAY, TimeUnit.MILLISECONDS));
        }
    
        private static FileWatchEvent.Type kindToType(WatchEvent.Kind kind) {
            if (StandardWatchEventKinds.ENTRY_CREATE.equals(kind))
                return FileWatchEvent.Type.ADDED;
            else if (StandardWatchEventKinds.ENTRY_MODIFY.equals(kind))
                return FileWatchEvent.Type.MODIFIED;
            else if (StandardWatchEventKinds.ENTRY_DELETE.equals(kind))
                return FileWatchEvent.Type.DELETED;
            throw new RuntimeException("Invalid kind: " + kind);
        }
    
        public static class FileWatchEvent {
            public enum Type {
                ADDED, DELETED, MODIFIED
            }
    
            private Type type;
            private Path path;
    
            public FileWatchEvent(Type type, Path path) {
                this.type = type;
                this.path = path;
            }
    
            public Type getType() {
                return type;
            }
    
            public Path getPath() {
                return path;
            }
    
            @Override
            public boolean equals(Object o) {
                if (this == o) return true;
                if (o == null || getClass() != o.getClass()) return false;
    
                FileWatchEvent that = (FileWatchEvent) o;
    
                if (type != that.type) return false;
                return path != null ? path.equals(that.path) : that.path == null;
            }
    
            @Override
            public int hashCode() {
                int result = type != null ? type.hashCode() : 0;
                result = 31 * result + (path != null ? path.hashCode() : 0);
                return result;
            }
        }
    }
    

提交回复
热议问题