Search code examples
javaniofile-watcher

how to watch multiple hard disk partitions in FileWacther in java


I am using FileWatcher to watch a whole hard disk partition in my case its D drive eg: D:/ the code is working fine with one path i provided, all i want is to watch other hard disk partitions as well like C:,D: and E: how can i achieve that here is the code

public class FileWatcher {
    private final WatchService watcher;
    private final Map<WatchKey, Path> keys;
    static Logger log = LoggerFactory.getLogger(GitCloneRepo.class);

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

        walkAndRegisterDirectories(dir);
    }

    /**
     * Register the given directory with the WatchService; This function will be called by FileVisitor
     */
    private void registerDirectory(Path dir) throws IOException
    {
        WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
        keys.put(key, dir);
    }

    /**
     * Register the given directory, and all its sub-directories, with the WatchService.
     */
    private void walkAndRegisterDirectories(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 {
                registerDirectory(dir);
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                if (exc instanceof AccessDeniedException) {
                    return FileVisitResult.SKIP_SUBTREE;
                }

                return super.visitFileFailed(file, exc);
            }
        });
    }

    /**
     * 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) {
                log.error("InterruptedException ",x);
                return;
            }

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

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

                // Context for directory entry event is the file name of entry
                @SuppressWarnings("unchecked")
                Path name = ((WatchEvent<Path>)event).context();
                Path child = dir.resolve(name);
                log.info("watching files");
                // print out event
                if (kind == ENTRY_MODIFY) {
                log.info("event.kind().name() {}: child {}", event.kind().name(), child);
                log.info("child {} ends with docx? {} ",child,child.endsWith(".docx"));
                String c= child.toString();
                log.info("**child {}***c.endsWith(.docx)"
                        + ""
                        + " {}",c,c.endsWith(".docx"));
                }
                // if directory is created, and watching recursively, then register it and its sub-directories
                if (kind == ENTRY_CREATE) {
                    try {
                        if (Files.isDirectory(child)) {
                            walkAndRegisterDirectories(child);
                        }
                    } catch (IOException x) {
                        // do something useful
                    }
                }
            }

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


 //working code
    public static void main(String[] args) throws IOException {
        try{
        Path dir = Paths.get("D:");
        FileWatcher fileWatcher=new FileWatcher(dir);
        fileWatcher.processEvents();
        }

        catch (AccessDeniedException xx) {
            log.error("AccessDeniedException  ",xx);
        }
         catch (FileSystemException x) {
            log.error("exception",x);
        }
        }

}

i looked at this question but i did not seemed to solve my problem How to implement file watcher to Watch multiple directories


Solution

  • Your processEvents method enters an infinite loop and doesn't return until either the thread is interrupted or the path is gone, which means any code after processEvents won't execute until it's done. If you want your main method to spin up multiple watchers, you'll need to call processEvents from other threads, e.g. with Java 8:

    // Create watchers
    List<FileWatcher> watchers = new ArrayList<>();
    try{
        watchers.add(new FileWatcher(Paths.get("D:")));
        watchers.add(new FileWatcher(Paths.get("E:")));
    } catch (AccessDeniedException xx) {
        log.error("AccessDeniedException  ",xx);
    } catch (FileSystemException x) {
        log.error("exception",x);
    }
    
    // Create and start threads
    List<Thread> threads = watchers.stream()
            .map(w -> new Thread(w::processEvents))
            .peek(Thread::start)
            .collect(Collectors.toList());
    

    With Java 7:

    // Create watchers
    List<FileWatcher> watchers = new ArrayList<>();
    try{
        watchers.add(new FileWatcher(Paths.get("D:")));
        watchers.add(new FileWatcher(Paths.get("E:")));
    } catch (AccessDeniedException xx) {
        log.error("AccessDeniedException  ",xx);
    } catch (FileSystemException x) {
        log.error("exception",x);
    }
    
    // Create and start threads
    List<Thread> threads = new ArrayList<>();
    for (FileWatcher watcher : watchers) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                watcher.processEvents();
            }
        });
        thread.start();
        threads.add(thread);
    }