监视服务获取文件句柄



我在应用程序中使用java watch服务来获得任何文件更改的通知。

但问题是监视服务持有父目录的文件句柄。例如,如果我的层次结构是

F
-F1
 -F2

当我在F、F1和F2上注册手表服务时。然后,如果我试图重命名或删除父文件夹F,则会出现另一个程序打开文件的消息,该程序是监视服务。

我发现这里提到了这个问题http://bugs.java.com/bugdatabase/view_bug.do;jsessionid=76a42b61021a94ffffffffa049f7587fd4149?bug_id=6972833

也尝试过使用File_Tree修饰符来规避这个问题,但没有帮助。可能我没有正确使用File_Tree修饰符。

下面是我正在测试的示例代码。请检查FILE_TREE修饰符在我的代码中的使用是否正确。

/**
 * Example to watch a directory (or tree) for changes to files.
 * This code is direct copy from https://docs.oracle.com/javase/tutorial/essential/io/examples/WatchDir.java
 */
public class FileWatcher {
    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, new WatchEvent.Kind[] { ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY, OVERFLOW },com.sun.nio.file.ExtendedWatchEventModifier.FILE_TREE);
        if (trace) {
            Path prev = keys.get(key);
            if (prev == null) {
                System.out.format("register: %sn", dir);
            } else {
                if (!dir.equals(prev)) {
                    System.out.format("update: %s -> %sn", 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
     */
    FileWatcher(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: %sn", 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 = false;
            dirArg++;
        }
        // register directory and process its events
        Path dir = Paths.get(args[dirArg]);
        new FileWatcher(dir, recursive).processEvents();
    }
}

深入研究文档,为自己找到解决方案。

使用File_Tree修改器,会为所有文件夹/目录指定一个键。所以我们需要使用一把钥匙。因此,我试图用相同的根路径重新注册,然后在监视目录下每次新创建项目时重用密钥。

主要的收获是

  1. 不再需要以递归方式查看目录中的每个文件夹
  2. 每当在根路径下创建新文件夹时,都需要在同一路径上重新注册,因为每次只需要密钥
  3. 我不确定性能部分,因为每次我都在注册整个路径。也许我会做一些性能分析

下面是我的代码的修改版本。如果代码不清楚,请告诉我

package com.sap.mcm;  
import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
import static java.nio.file.StandardWatchEventKinds.OVERFLOW;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashMap;
import java.util.Map;
import com.sun.nio.file.ExtendedWatchEventModifier;
/**
 * Example to watch a directory (or tree) for changes to files.
 * This code is direct copy from https://docs.oracle.com/javase/tutorial/essential/io/examples/WatchDir.java
 */
public class FileWatcher {
    private final WatchService watcher;
    private final Map<WatchKey,Path> keys;
    private final boolean recursive;
    private boolean trace = true;
    private Path parentDir;
    private WatchKey key;
    @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 {
        try {
            parentDir = dir;
            key = parentDir.register(watcher, new WatchEvent.Kind[] { ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY, OVERFLOW }, ExtendedWatchEventModifier.FILE_TREE);
        } catch (UnsupportedOperationException usoe) {
            usoe.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void reregister() throws IOException {
        // WatchKey key = keys.get(path);
        key.cancel();
        register(parentDir);
    }
    /**
     * 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
     */
    FileWatcher(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;
            // }
            if (this.key != key) {
                return;
            }
            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);
                ev.context();
                // print out event
                System.out.format("%s: %s n", event.kind().name(), event.context());
                // if directory is created, and watching recursively, then
                // register it and its sub-directories
                if (kind == ENTRY_CREATE) {
                    try {
                        // if (Files.isDirectory(child, NOFOLLOW_LINKS)) {
                        reregister();
                        // }
                    } catch (IOException x) {
                        // ignore to keep sample readbale
                    }
                }
            }
            // reset key and remove from set if directory no longer accessible
            boolean valid = this.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 = false;
            dirArg++;
        }
        // register directory and process its events
        Path dir = Paths.get(args[dirArg]);
        new FileWatcher(dir, recursive).processEvents();
    }
}

相关内容

  • 没有找到相关文章

最新更新