44

のjavadocはStandardWatchEventKinds.ENTRY_MODIFY言う:

ディレクトリ エントリが変更されました。このイベントに対してディレクトリが登録されると、ディレクトリ内のエントリが変更されたことが確認されると、WatchKey がキューに入れられます。このイベントのイベント数は 1 以上です。

エディターを使用してファイルのコンテンツを編集すると、日付 (または他のメタデータ) とコンテンツの両方が変更されます。したがって、2 つのENTRY_MODIFYイベントが発生しますが、それぞれのイベントcountは 1 になります (少なくとも、これは私が見ているものです)。

次のコードを使用して手動で更新された (つまり、コマンド ラインを介して)構成ファイル (servers.cfg以前に に登録された)を監視しようとしています。WatchServicevi

while(true) {
    watchKey = watchService.take(); // blocks

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

        System.out.println(watchEvent.context() + ", count: "+ watchEvent.count() + ", event: "+ watchEvent.kind());
        // prints (loop on the while twice)
        // servers.cfg, count: 1, event: ENTRY_MODIFY
        // servers.cfg, count: 1, event: ENTRY_MODIFY

        switch(kind.name()) {
            case "ENTRY_MODIFY":
                handleModify(watchEvent.context()); // reload configuration class
                break;
            case "ENTRY_DELETE":
                handleDelete(watchEvent.context()); // do something else
                break;              
        }
    }   

    watchKey.reset();       
}

2 つのイベントを取得するためENTRY_MODIFY、上記では、1 回だけ必要な場合に構成を 2 回リロードします。そのようなイベントが複数存在する可能性があると仮定して、これらの 1 つを除くすべてを無視する方法はありますか?

WatchServiceAPI にそのようなユーティリティがある場合は、はるかに優れています。(各イベント間の時間をチェックしたくありません。コード内のすべてのハンドラー メソッドは同期的です。

あるディレクトリから監視対象のディレクトリにファイルを作成 (コピー/貼り付け) すると、同じことが起こります。両方を 1 つのイベントにまとめるにはどうすればよいでしょうか。

4

15 に答える 15

16

同様の問題がありました。WatchService API を使用してディレクトリの同期を維持していますが、多くの場合、更新が 2 回実行されていることがわかりました。ファイルのタイムスタンプを確認することで問題を解決したようです-これにより、2番目のコピー操作が除外されるようです。(少なくとも Windows 7 では - 他のオペレーティング システムで正しく動作するかどうかはわかりません)

多分あなたは似たようなものを使うことができますか?ファイルからタイムスタンプを保存し、タイムスタンプが更新されたときにのみリロードしますか?

于 2013-06-04T11:03:29.650 に答える
6

このような問題に対する私の解決策の 1 つは、単純に一意のイベント リソースをキューに入れ、許容できる時間だけ処理を遅らせることです。この場合Set<String>、到着する各イベントから派生したすべてのファイル名を含む を維持します。を使用Set<>すると、重複が追加されないため、(遅延期間ごとに) 1 回だけ処理されます。

興味深いイベントが到着するたびに、ファイル名を に追加しSet<>、遅延タイマーを再起動します。事態が落ち着き、遅延期間が経過すると、ファイルの処理に進みます。

addFileToProcess() および processFiles() メソッドは、ConcurrentModificationExceptions がスローされないように「同期」されます。

この単純化された/スタンドアロンの例は、Oracle のWatchDir.javaの派生物です。

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.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

public class DirectoryWatcherService implements Runnable {
    @SuppressWarnings("unchecked")
    static <T> WatchEvent<T> cast(WatchEvent<?> event) {
        return (WatchEvent<T>)event;
    }

    /*
     * Wait this long after an event before processing the files.
     */
    private final int DELAY = 500;

    /*
     * Use a SET to prevent duplicates from being added when multiple events on the 
     * same file arrive in quick succession.
     */
    HashSet<String> filesToReload = new HashSet<String>();

    /*
     * Keep a map that will be used to resolve WatchKeys to the parent directory
     * so that we can resolve the full path to an event file. 
     */
    private final Map<WatchKey,Path> keys;

    Timer processDelayTimer = null;

    private volatile Thread server;

    private boolean trace = false;

    private WatchService watcher = null;

    public DirectoryWatcherService(Path dir, boolean recursive) 
        throws IOException {
        this.watcher = FileSystems.getDefault().newWatchService();
        this.keys = new HashMap<WatchKey,Path>();

        if (recursive) {
            registerAll(dir);
        } else {
            register(dir);
        }

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

    private synchronized void addFileToProcess(String filename) {
        boolean alreadyAdded = filesToReload.add(filename) == false;
        System.out.println("Queuing file for processing: " 
            + filename + (alreadyAdded?"(already queued)":""));
        if (processDelayTimer != null) {
            processDelayTimer.cancel();
        }
        processDelayTimer = new Timer();
        processDelayTimer.schedule(new TimerTask() {

            @Override
            public void run() {
                processFiles();
            }
        }, DELAY);
    }

    private synchronized void processFiles() {
        /*
         * Iterate over the set of file to be processed
         */
        for (Iterator<String> it = filesToReload.iterator(); it.hasNext();) {
            String filename = it.next();

            /*
             * Sometimes you just have to do what you have to do...
             */
            System.out.println("Processing file: " + filename);

            /*
             * Remove this file from the set.
             */
            it.remove();
        }
    }

    /**
     * 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
            {
                if (dir.getFileName().toString().startsWith(".")) {
                    return FileVisitResult.SKIP_SUBTREE;
                }

                register(dir);
                return FileVisitResult.CONTINUE;
            }
        });
    }

    @SuppressWarnings("unchecked")
    @Override
    public void run() {
        Thread thisThread = Thread.currentThread();

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

                Path dir = keys.get(key);
                if (dir == null) {
                    continue;
                }

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

                    if (kind == OVERFLOW) {
                        continue;
                    }

                    if (kind == ENTRY_MODIFY) {

                        WatchEvent<Path> ev = (WatchEvent<Path>)event;
                        Path name = ev.context();
                        Path child = dir.resolve(name);

                        String filename = child.toAbsolutePath().toString();

                        addFileToProcess(filename);
                    }
                }

                key.reset();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void start() {
        server = new Thread(this);
        server.setName("Directory Watcher Service");
        server.start();
    }


    public void stop() {
        Thread moribund = server;
        server = null;
        if (moribund != null) {
            moribund.interrupt();
        }
    }

    public static void main(String[] args) {
        if (args==null || args.length == 0) {
            System.err.println("You need to provide a path to watch!");
            System.exit(-1);
        }

        Path p = Paths.get(args[0]);
        if (!Files.isDirectory(p)) {
            System.err.println(p + " is not a directory!");
            System.exit(-1);
        }

        DirectoryWatcherService watcherService;
        try {
            watcherService = new DirectoryWatcherService(p, true);
            watcherService.start();
        } catch (IOException e) {
            System.err.println(e.getMessage());
        }
    }

}
于 2016-01-15T19:41:15.883 に答える
3

timestamps複数のイベントの発生を避けるために使用する完全な実装を次に示します。

import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashMap;
import java.util.Map;

import static java.nio.file.LinkOption.NOFOLLOW_LINKS;
import static java.nio.file.StandardWatchEventKinds.*;

public abstract class DirectoryWatcher
{
    private WatchService watcher;
    private Map<WatchKey, Path> keys;
    private Map<Path, Long> fileTimeStamps;
    private boolean recursive;
    private boolean trace = true;

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

    /**
     * Register the given directory with the WatchService
     */
    private void register(Path directory) throws IOException
    {
        WatchKey watchKey = directory.register(watcher, ENTRY_MODIFY, ENTRY_CREATE, ENTRY_DELETE);

        addFileTimeStamps(directory);

        if (trace)
        {
            Path existingFilePath = keys.get(watchKey);
            if (existingFilePath == null)
            {
                System.out.format("register: %s\n", directory);
            } else
            {
                if (!directory.equals(existingFilePath))
                {
                    System.out.format("update: %s -> %s\n", existingFilePath, directory);
                }
            }
        }

        keys.put(watchKey, directory);
    }

    private void addFileTimeStamps(Path directory)
    {
        File[] files = directory.toFile().listFiles();
        if (files != null)
        {
            for (File file : files)
            {
                if (file.isFile())
                {
                    fileTimeStamps.put(file.toPath(), file.lastModified());
                }
            }
        }
    }

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

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

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

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

    /**
     * Process all events for keys queued to the watcher
     */
    void processEvents() throws InterruptedException, IOException
    {
        while (true)
        {
            WatchKey key = watcher.take();

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

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

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

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

                long oldFileModifiedTimeStamp = fileTimeStamps.get(filePath);
                long newFileModifiedTimeStamp = filePath.toFile().lastModified();
                if (newFileModifiedTimeStamp > oldFileModifiedTimeStamp)
                {
                    fileTimeStamps.remove(filePath);
                    onEventOccurred();
                    fileTimeStamps.put(filePath, filePath.toFile().lastModified());
                }

                if (recursive && watchEventKind == ENTRY_CREATE)
                {
                    if (Files.isDirectory(filePath, NOFOLLOW_LINKS))
                    {
                        registerAll(filePath);
                    }
                }

                break;
            }

            boolean valid = key.reset();

            if (!valid)
            {
                keys.remove(key);

                if (keys.isEmpty())
                {
                    break;
                }
            }
        }
    }

    public abstract void onEventOccurred();
}

クラスを拡張してonEventOccurred()メソッドを実装します。

于 2016-11-16T20:56:34.140 に答える
2

jdk7に問題がありますか? それは私にとって正しい結果をもたらします(jdk7u15、windows)

コード

import java.io.IOException;
import java.nio.file.*;

public class WatchTest {

    public void watchMyFiles() throws IOException, InterruptedException {
        Path path = Paths.get("c:/temp");
        WatchService watchService = path.getFileSystem().newWatchService();
        path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);

        while (true) {
            WatchKey watchKey = watchService.take(); // blocks

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

                System.out.println(watchEvent.context() + ", count: " +
                        watchEvent.count() + ", event: " + watchEvent.kind());
                // prints (loop on the while twice)
                // servers.cfg, count: 1, event: ENTRY_MODIFY
                // servers.cfg, count: 1, event: ENTRY_MODIFY

                switch (kind.name()) {
                    case "ENTRY_MODIFY":
                        handleModify(watchEvent.context()); // reload configuration class
                        break;
                    case "ENTRY_DELETE":
                        handleDelete(watchEvent.context()); // do something else
                        break;
                    default:
                        System.out.println("Event not expected " + event.kind().name());
                }
            }

            watchKey.reset();
        }
    }

    private void handleDelete(Path context) {
        System.out.println("handleDelete  " + context.getFileName());
    }

    private void handleModify(Path context) {
        System.out.println("handleModify " + context.getFileName());
    }

    public static void main(String[] args) throws IOException, InterruptedException {
        new WatchTest().watchMyFiles();
    }
}

出力は次のようになります-ファイルがメモ帳を使用してコピーまたは編集された場合。

config.xml, count: 1, event: ENTRY_MODIFY
handleModify config.xml

Vi は多くの追加ファイルを使用し、ファイル属性を複数回更新しているようです。notepad++ は正確に 2 回行います。

于 2013-06-11T05:47:46.287 に答える
2

RxJava を使用する場合は、オペレーターの throttleLast を使用できます。以下の例では、監視対象ディレクトリ内の各ファイルに対して、1000 ミリ秒の最後のイベントのみが発行されます。

public class FileUtils {
    private static final long EVENT_DELAY = 1000L;

    public static Observable<FileWatchEvent> watch(Path directory, String glob) {
        return Observable.<FileWatchEvent>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<Path> ev = (WatchEvent<Path>) 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;
        }
    }
}
于 2017-07-22T09:11:11.567 に答える
1

Oracle のWatchDir.javaと @nilesh の提案をObservable、監視対象のファイルが変更されたときに一度オブザーバーに通知するクラスにコンパイルしました。

できるだけ読みやすく短くしようとしましたが、それでも 100 行以上になりました。もちろん、改善は大歓迎です。

使用法:

FileChangeNotifier fileReloader = new FileChangeNotifier(File file);
fileReloader.addObserver((Observable obj, Object arg) -> {
    System.out.println("File changed for the " + arg + " time.");
});

GitHub で私のソリューションを参照してください: FileChangeNotifier.java 。

于 2015-07-31T11:59:49.080 に答える
1

デフォルトでfalseである「modifySolver」という名前のグローバルブール変数を定義することで、この問題を解決しました。以下に示すように、この問題を処理できます。

else if (eventKind.equals (ENTRY_MODIFY))
        {
            if (event.count() == 2)
            {
                getListener(getDirPath(key)).onChange (FileChangeType.MODIFY, file.toString ());
            }
            /*capture first modify event*/
            else if ((event.count() == 1) && (!modifySolver))
            {
                getListener(getDirPath(key)).onChange (FileChangeType.MODIFY, file.toString ());
                modifySolver = true;
            }
            /*discard the second modify event*/
            else if ((event.count() == 1) && (modifySolver))
            {
                modifySolver = false;
            }
        }
于 2016-05-10T05:51:16.367 に答える
0

同様の問題がありました。私はこれが遅いことを知っていますが、誰かを助けるかもしれません. 重複を排除する必要がありましたENTRY_MODIFY。ENTRY_MODIFY がトリガーされるたびcount()に、2 または 1 のいずれかが返されます。1 の場合は、1 の別のイベントが発生しcount()ます。したがって、戻り値のカウントを保持するグローバル カウンターを配置し、カウンターが 2 になったときにのみ操作を実行します。このようなことができます:

WatchEvent event; 
int count = 0;

if(event.count() == 2)
     count = 2;

if(event.count() == 1)
     count++;

if(count == 2){
     //your operations here
     count = 0;
}
于 2015-11-05T14:17:15.950 に答える
0

複数のイベントのセットは、ファイルの作成/変更に使用されるツールによって異なります。

1.Vimで新規ファイル作成

MODIFIED、CREATED イベントが発生する

2.Vimでファイルを修正

DELETED、MODIFIED、CREATED イベントが発生する

3.Linuxコマンド「mv」を使用して、ファイルを他のフォルダーから監視フォルダーに移動します

MODIFIED イベントが発生する

4.Linuxコマンド「cp」を使用して、ファイルを他のフォルダーから監視フォルダーにコピーします

同じファイル名のファイルが存在しない場合、MODIFIED、CREATED が実行されます。同じファイル名のファイルが存在する場合、CREATED が実行されます。

3 つのマップを使用して、WatchEvent を反復する for ループで CREATED/MODIFIED/DELETED エントリを収集しました。次に、これら 3 つのマップに対して 3 つの for ループを実行して、通知する必要がある正しいイベントを特定します (例: ファイル名が 3 つのマップすべてに表示される場合、それは MODIFIED イベントであると言えます)。

            File f = new File(sourceDir);
        if (!f.exists() || !f.isDirectory()) {
            LOGGER.warn("File " + sourceDir + " does not exist OR is not a directory");
            return;
        }
        WatchService watchService = FileSystems.getDefault().newWatchService();
        Path watchedDir = f.toPath();
        watchedDir.register(watchService, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);

        while (true) {
            try {
                WatchKey watchKey = watchService.take();

                Thread.sleep(checkInterval);

                //Events fired by Java NIO file watcher depends on the tool used
                //to create/update/delete file. We need those 3 maps to collect
                //all entries fired by NIO watcher. Then, make 3 loops at the end
                //to determine the correct unique event to notify
                final Map<String, Boolean> createdEntries = new HashMap<>();
                final Map<String, Boolean> modifiedEntries = new HashMap<>();
                final Map<String, Boolean> deletedEntries = new HashMap<>();

                List<WatchEvent<?>> events = watchKey.pollEvents();
                for (WatchEvent<?> event : events) {
                    if (event.kind() == OVERFLOW) {
                        continue;
                    }

                    WatchEvent<Path> pathEvent = (WatchEvent<Path>) event;
                    WatchEvent.Kind<Path> kind = pathEvent.kind();

                    Path path = pathEvent.context();
                    String fileName = path.toString();
                    if (accept(fileName)) {
                        if (kind == ENTRY_CREATE) {
                            createdEntries.put(fileName, true);
                        } else if (kind == ENTRY_MODIFY) {
                            modifiedEntries.put(fileName, true);
                        } else if (kind == ENTRY_DELETE) {
                            deletedEntries.put(fileName, true);
                        }
                    }
                }

                long timeStamp = System.currentTimeMillis();
                final Map<String, Boolean> handledEntries = new HashMap<>();

                //3 for loops to determine correct event to notify
                for (String key : createdEntries.keySet()) {
                    if (handledEntries.get(key) == null) {
                        Boolean modified = modifiedEntries.get(key);
                        Boolean deleted = deletedEntries.get(key);
                        if (modified != null && deleted != null) {
                            //A triplet of DELETED/MODIFIED/CREATED means a MODIFIED event
                            LOGGER.debug("File " + key + " was modified");
                            notifyFileModified(key, timeStamp);
                        } else if (modified != null) {
                            LOGGER.debug("New file " + key + " was created");
                            notifyFileCreated(key, timeStamp);
                        } else {
                            LOGGER.debug("New file " + key + " was created");
                            notifyFileCreated(key, timeStamp);
                        }
                        handledEntries.put(key, true);
                    }
                }

                for (String key : modifiedEntries.keySet()) {
                    if (handledEntries.get(key) == null) {
                        //Current entry survives from loop on CREATED entries. It is certain
                        //that we have MODIFIED event
                        LOGGER.debug("File " + key + " was modified");
                        notifyFileModified(key, timeStamp);
                        handledEntries.put(key, true);
                    }

                }

                for (String key : deletedEntries.keySet()) {
                    if (handledEntries.get(key) == null) {
                        //Current entry survives from two loops on CREATED/MODIFIED entries. It is certain
                        //that we have DELETE event
                        LOGGER.debug("File " + key + " was deleted");
                        notifyFileDeleted(key, timeStamp);
                    }
                }

                boolean valid = watchKey.reset();
                if (!valid) {
                    break;
                }
            } catch (Exception ex) {
                LOGGER.warn("Error while handling file events under: " + sourceDir, ex);
            }

            Thread.sleep(checkInterval);
        }
于 2021-08-14T07:55:18.737 に答える
-1

テストされていませんが、おそらくこれでうまくいくでしょう:

AtomicBoolean modifyEventFired = new AtomicBoolean();
modifyEventFired.set(false);

while(true) {
    watchKey = watchService.take(); // blocks

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

        System.out.println(watchEvent.context() + ", count: "+ watchEvent.count() + ", event: "+ watchEvent.kind());
        // prints (loop on the while twice)
        // servers.cfg, count: 1, event: ENTRY_MODIFY
        // servers.cfg, count: 1, event: ENTRY_MODIFY

        switch(kind.name()) {
            case "ENTRY_MODIFY":
                if(!modifyEventFired.get()){
                   handleModify(watchEvent.context()); // reload configuration class
                   modifyEventFired.set(true);                           
                }
                break;
            case "ENTRY_DELETE":
                handleDelete(watchEvent.context()); // do something else
                break;              
        }
    }   
    modifyEventFired.set(false);
    watchKey.reset();       
}
于 2013-05-27T20:37:31.663 に答える