Часовой сервис получает дескриптор файла

Я использую службу наблюдения Java в своем приложении, чтобы получать уведомления о любых изменениях файлов.

Но проблема в том, что служба часов хранит дескриптор файла родительского каталога. Например, если моя иерархия

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: %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
     */
    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: %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 = false;
            dirArg++;
        }

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

1 ответ

Покопайся немного в документах и ​​найди решение для себя.

С модификатором 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();
    }
}
Другие вопросы по тегам