用于多个目录的Java nio WatchService

时间:2013-03-20 07:22:21

标签: java nio java-7

我想使用Java NIO WatchService观看(监控)多个目录。 我的问题是要监视的目录数是动态的,用户可以向WatchService添加任意数量的目录。这可以实现吗?

4 个答案:

答案 0 :(得分:8)

可以使用相同的WatchService注册多个路径。每条路径都有自己的WatchKey。然后,take()poll()将返回与修改后的路径对应的WatchKey

有关详细信息,请参阅Java's WatchDir example

答案 1 :(得分:2)

我只想解释如何使用WatchService完成此操作。

以下是一段代码,说明了如何使用一个WatchService实例并听取两个Paths

        this.watcher = FileSystems.getDefault().newWatchService();
        this.keys = new HashMap<>();

        Path plugins = Paths.get(INSTANCE.getPluginPath());
        logger.info(String.format("Scanning %s ...", plugins));
        registerAll(plugins);

        Path drivers = Paths.get(INSTANCE.getDriverPath());
        logger.info(String.format("Scanning %s ...", drivers));
        registerAll(drivers);

该示例基于Oracle Example

答案 2 :(得分:2)

遵循与先前答案相同的链接:Oracle WatchDir

您可以先创建WatchService

WatchService watchService = FileSystems.getDefault().newWatchService();

目前,您可以将多个路径添加到同一WatchService

Path path1 = Paths.get("full\path\1\\");
path1.register(watchService,
               StandardWatchEventKinds.ENTRY_CREATE);

Path path2 = Paths.get("full\path\2\\");
path2.register(watchService,
               StandardWatchEventKinds.ENTRY_CREATE);

然后您可以按以下方式管理事件:

WatchKey key;
while ((key = watchService.take()) != null) {
    for (WatchEvent<?> event : key.pollEvents()) {
        System.out.println(
          "Event kind:" + event.kind() 
            + ". File affected: " + event.context() + ".");
    }
    key.reset();
}

现在,如果您想获得有关在何处引发事件的更多信息,则可以创建一个映射以通过示例链接键和路径(您可以根据需要考虑将变量创建为类级别):

Map<WatchKey, Path> keys;

在此示例中,您可以将路径包含在列表中,然后需要循环到其中,并将每个路径添加到相同的WatchService

for (Path path : paths) {
    WatchKey key = path.register(
            watchService,
            StandardWatchEventKinds.ENTRY_CREATE);
    keys.put(key, path);
}

现在可以管理事件了,您可以添加类似的内容:

WatchKey key;
while ((key = watchService.take()) != null) {
    Path path = keys.get(key);
    // More code here.
    key.reset();
}

答案 3 :(得分:0)

为几个固定目录添加一个完整的简单解决方案。这个例子有 3 个将被监控的目录,当我正在寻找一个文件时,我会处理它。在 Linux 中使用这种方法而不是我需要 root 访问权限的端口侦听器。

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 java.io.File;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.HashMap;
import java.util.Map;

public class WatchDirSimple {
    
    public static void main(String[] args) {
        try {
            
            WatchService watcher = FileSystems.getDefault().newWatchService();
            Map<WatchKey,Path> keys = new HashMap<WatchKey,Path>();
            
            WatchDirSimple watchDirSimple = new WatchDirSimple();
            
            WatchKey key;
            Path dir;
            
            dir = Paths.get(System.getProperty("user.home")+File.separator + "Documents\\PROD_Data\\ODBI");
            key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
            keys.put(key, dir);
            dir = Paths.get(System.getProperty("user.home")+File.separator + "Documents\\PROD_Data\\ODBI\\@fred");
            key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
            keys.put(key, dir);
            dir = Paths.get(System.getProperty("user.home")+File.separator + "Documents\\PROD_Data\\ODBI\\CMODupgrade");
            key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
            keys.put(key, dir);
            
            for (;;) {

                try {
                    key = watcher.take();
                } catch (InterruptedException x) {
                    return;
                }

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

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

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

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

                // 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;
                    }
                }
            }

            watchDirSimple.register(dir, watcher, keys);
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}