Watching a Directory for Changes in Java

前端 未结 6 464
灰色年华
灰色年华 2020-11-29 03:01

I want to watch a directory for file changes. And I used WatchService in java.nio. I can successfully listen for file created event. But I can\'t listen for file modify even

相关标签:
6条回答
  • 2020-11-29 03:11
    public class FileWatcher implements Runnable {
    
    private static final Logger LOGGER =Logger.getLogger(FileWatcher.class.getName());
    
    private WatchService watcher;
    private FileHandler fileHandler;
    private List<Kind<?>> watchedEvents;
    private Path directoryWatched;
    
    /**
     * @param directory
     * @Path directory to watch files into
     * @param fileHandler
     * @FileHandler implemented instance to handle the file event
     * @param watchRecursive
     *            if directory is to be watched recursively
     * @param watchedEvents
     *            Set of file events watched
     * 
     * @throws IOException
     */
    public FileWatcher(Path directory, FileHandler fileHandler, boolean watchRecursive,
            WatchEvent.Kind<?>... watchedEvents) throws IOException {
        super();
        this.watcher = FileSystems.getDefault().newWatchService();
        this.fileHandler = fileHandler;
        this.directoryWatched = directory;
        this.watchedEvents = Arrays.asList(watchedEvents);
        if (watchRecursive) {
            // register all subfolders
            Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                    LOGGER.log(Level.INFO, "Registering {0} ", dir);
                    dir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE,
                            StandardWatchEventKinds.ENTRY_MODIFY);
                    return FileVisitResult.CONTINUE;
                }
            });
        } else {
            directory.register(watcher, watchedEvents);
        }
    }
    
    @SuppressWarnings({ "unchecked" })
    public void run() {
        LOGGER.log(Level.INFO, "Starting FileWatcher for {0}", directoryWatched.toAbsolutePath());
        WatchKey key = null;
        while (true) {
            try {
                key = watcher.take();
                if (key != null) {
                    for (WatchEvent<?> event : key.pollEvents()) {
                        WatchEvent.Kind<?> kind = event.kind();
    
                        WatchEvent<Path> ev = (WatchEvent<Path>) event;
                        //directory in which file event is detected
                        Path directory = (Path) key.watchable(); 
                        Path fileName = ev.context();
                        if (watchedEvents.contains(kind)) {
                            LOGGER.log(Level.INFO, "Invoking handle on {0}", fileName.toAbsolutePath());
                            fileHandler.handle(directory.resolve(fileName).toFile(), kind);
                        }
                    }
                    key.reset();
                }
            } catch (InterruptedException ex) {
                LOGGER.log(Level.SEVERE, "Polling Thread was interrupted ", ex);
                Thread.currentThread().interrupt();
            }
        }
    }
    

    }

    0 讨论(0)
  • 2020-11-29 03:12
    package p1;
    
    import java.io.File;
    import java.io.IOException;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    import static java.nio.file.LinkOption.NOFOLLOW_LINKS;
    import java.nio.file.StandardWatchEventKinds;
    import java.nio.file.WatchEvent;
    import java.nio.file.WatchKey;
    import java.nio.file.WatchService;
    import java.util.List;
    
    public class WatchForFile {
    
        public void WatchMyFolder(String path )
        {
            File dir = new File(path);
            Path myDir= dir.toPath();
              try 
              {
                  Boolean isFolder = (Boolean) Files.getAttribute(myDir,"basic:isDirectory", NOFOLLOW_LINKS);
                  if (!isFolder)
                  {
                      throw new IllegalArgumentException("Path: " + myDir + " is not a folder");
                  }
              }
              catch (IOException ioe)
              {
                  ioe.printStackTrace();
              }
    
              System.out.println("Watching path: " + myDir);
    
            try {
               WatchService watcher = myDir.getFileSystem().newWatchService();
               myDir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE,StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY);
    
               WatchKey watckKey = watcher.take();
    
               List<WatchEvent<?>> events = watckKey.pollEvents();
    
               for (WatchEvent event : events) {
                    if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE) {
                        System.out.println("Created: " + event.kind().toString());
    
                    }
                    if (event.kind() == StandardWatchEventKinds.ENTRY_DELETE) {
                        System.out.println("Delete: " + event.context().toString());
                    }
                    if (event.kind() == StandardWatchEventKinds.ENTRY_MODIFY) {
                        System.out.println("Modify: " + event.context().toString());
                    }
                }
    
            }
            catch (Exception e) 
            {
                System.out.println("Error: " + e.toString());
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-29 03:26

    I made some classes for this.

    public interface FileAvailableListener {
        public void fileAvailable(File file) throws IOException;
    }
    

    and

    public class FileChange {
    
    private long lastModified;
    private long size;
    private long lastCheck;
    
    public FileChange(File file) {
        this.lastModified=file.lastModified();
        this.size=file.length();
        this.lastCheck = System.currentTimeMillis();
    }
    
    public long getLastModified() {
        return lastModified;
    }
    public long getSize() {
        return size;
    }
    public long getLastCheck() {
        return lastCheck;
    }
    
    public boolean isStable(FileChange other,long stableTime) {
        boolean b1 = (getLastModified()==other.getLastModified());
        boolean b2 = (getSize()==other.getSize());
        boolean b3 = ((other.getLastCheck()-getLastCheck())>stableTime);
        return b1 && b2 && b3;
    }
    }
    

    and

    public class DirectoryWatcher {
    
    private Timer timer;
    private List<DirectoryMonitorTask> tasks = new ArrayList<DirectoryMonitorTask>();
    
    public DirectoryWatcher() throws URISyntaxException, IOException, InterruptedException {
        super();
        timer = new Timer(true);        
    }
    public void addDirectoryMonitoringTask(DirectoryMonitorTask task,long period) {
        tasks.add(task);
        timer.scheduleAtFixedRate(task, 5000, period);      
    }
    public List<DirectoryMonitorTask> getTasks() {
        return Collections.unmodifiableList(tasks);
    }
    public Timer getTimer() {
        return timer;
    }
    }
    

    and

    class DirectoryMonitorTask extends TimerTask {
    
    public final static String DIRECTORY_NAME_ARCHIVE="archive";
    public final static String DIRECTORY_NAME_ERROR="error";
    public final static String LOCK_FILE_EXTENSION=".lock";
    public final static String ERROR_FILE_EXTENSION=".error";   
    public final static String FILE_DATE_FORMAT="yyyyMMddHHmmssSSS";
    
    private String name;
    private FileAvailableListener listener;
    private Path directory;
    private File directoryArchive;
    private File directoryError;
    private long stableTime;
    private FileFilter filter;
    private WatchService watchService;
    private SimpleDateFormat dateFormatter = new SimpleDateFormat(FILE_DATE_FORMAT);
    private Hashtable<File,FileChange> fileMonitor = new Hashtable<File,FileChange>();
    
    public DirectoryMonitorTask(String name,FileAvailableListener listener,Path directory,long stableTime,FileFilter filter) throws IOException {
        super();
        this.name=name;
        this.listener=listener;
        this.directory=directory;
        this.stableTime=stableTime;
        if (stableTime<1) {
            stableTime=1000;
        }
        this.filter=filter;
        validateNotNull("Name",name);
        validateNotNull("Listener",listener);
        validateNotNull("Directory",directory);
        validate(directory);
        directoryArchive = new File(directory.toFile(),DIRECTORY_NAME_ARCHIVE);
        directoryError = new File(directory.toFile(),DIRECTORY_NAME_ERROR);
        directoryArchive.mkdir();
        directoryError.mkdir();
        //
        log("Constructed for "+getDirectory().toFile().getAbsolutePath());
    
        initialize();
        //
        watchService = FileSystems.getDefault().newWatchService();
        directory.register(watchService,StandardWatchEventKinds.ENTRY_CREATE,StandardWatchEventKinds.ENTRY_DELETE,StandardWatchEventKinds.ENTRY_MODIFY);
        log("Started");
    }
    
    private void initialize() {
        File[] files = getDirectory().toFile().listFiles();
        for (File file : files) {
            if (isLockFile(file)) {
                file.delete();
            } else if (acceptFile(file)) {
                fileMonitor.put(file,new FileChange(file));
                log("Init file added -"+file.getName());
            }
        }
    }
    public SimpleDateFormat getDateFormatter() {
        return dateFormatter;
    }
    public Path getDirectory() {
        return directory;
    }
    public FileAvailableListener getListener() {
        return listener;
    }
    public String getName() {
        return name;
    }
    public WatchService getWatchService() {
        return watchService;
    }
    public long getStableTime() {
        return stableTime;
    }
    public File getDirectoryArchive() {
        return directoryArchive;
    }
    public File getDirectoryError() {
        return directoryError;
    }
    public FileFilter getFilter() {
        return filter;
    }   
    public Iterator<File> getMonitoredFiles() {
        return fileMonitor.keySet().iterator();
    }
    
    @Override
    public void run() {
        WatchKey key;
        try {
            key = getWatchService().take();
            // Poll all the events queued for the key
            for (WatchEvent<?> event : key.pollEvents()) {                                      
                @SuppressWarnings("unchecked")
                Path filePath = ((WatchEvent<Path>) event).context();
                File file = filePath.toFile();
                if ((!isLockFile(file)) && (acceptFile(file))) {
                    switch (event.kind().name()) {
                        case "ENTRY_CREATE":
                            //                          
                            fileMonitor.put(file,new FileChange(file));
                            log("File created ["+file.getName()+"]");
                            break;
                            //
                        case "ENTRY_MODIFY":
                            //                          
                            fileMonitor.put(file,new FileChange(file));
                            log("File modified ["+file.getName()+"]");
                            break;  
                            //
                        case "ENTRY_DELETE":
                            //
                            log("File deleted ["+file.getName()+"]");
                            createLockFile(file).delete();
                            fileMonitor.remove(file);                           
                            break;
                            //
                    }
                }
            }
            // reset is invoked to put the key back to ready state
            key.reset();
        } catch (InterruptedException e) {              
            e.printStackTrace();
        }
    
        Iterator<File> it = fileMonitor.keySet().iterator();
    
        while (it.hasNext()) {
            File file = it.next();  
            FileChange fileChange = fileMonitor.get(file);
            FileChange fileChangeCurrent = new FileChange(file);
    
            if (fileChange.isStable(fileChangeCurrent, getStableTime())) {
                log("File is stable ["+file.getName()+"]");
                String filename = getDateFormatter().format(new Date())+"_"+file.getName();
                File lockFile = createLockFile(file);
                if (!lockFile.exists()) {
                    log("File do not has lock file ["+file.getName()+"]");
                    try {
                        Files.createFile(lockFile.toPath());
                        log("Processing file ["+file.getName()+"]");
                        getListener().fileAvailable(file);                      
                        file.renameTo(new File(getDirectoryArchive(),filename));
                        log("Moved to archive file ["+file.getName()+"]");
                    } catch (IOException e) {                       
                        file.renameTo(new File(getDirectoryError(),filename));
                        createErrorFile(file,e);
                        log("Moved to error file ["+file.getName()+"]");
                    } finally {
                        lockFile.delete();
    
                    }
                } else {                    
                    log("File do has lock file ["+file.getName()+"]");
                    fileMonitor.remove(file);
                }               
            } else {                
                log("File is unstable ["+file.getName()+"]");
                fileMonitor.put(file,fileChangeCurrent);
            }
        }       
    }
    
    public boolean acceptFile(File file) {
        if (getFilter()!=null) {
            return getFilter().accept(file);
        } else {
            return true;
        }       
    }
    
    public boolean isLockFile(File file) {
        int pos = file.getName().lastIndexOf('.');
        String extension="";
        if (pos!=-1) {
            extension = file.getName().substring(pos).trim().toLowerCase();
        }   
        return(extension.equalsIgnoreCase(LOCK_FILE_EXTENSION));
    }
    
    private File createLockFile(File file) {
        return new File(file.getParentFile(),file.getName()+LOCK_FILE_EXTENSION);
    }
    
    private void createErrorFile(File file,IOException exception) {
        File errorFile = new File(file.getParentFile(),file.getName()+ERROR_FILE_EXTENSION);
    
        StringWriter sw = null;
        PrintWriter pw = null;
        FileWriter fileWriter = null;
        try {
            //          
            fileWriter = new FileWriter(errorFile);
            if (exception!=null) {
                sw = new StringWriter();
                pw = new PrintWriter(sw);
                exception.printStackTrace(pw);      
                fileWriter.write(sw.toString());
            } else {
                fileWriter.write("Exception is null.");
            }
            //      
            fileWriter.flush();
            //
        } catch (IOException e) {
        } finally {
            if (sw!=null) {
                try {
                    sw.close();
                } catch (IOException e1) {              
                }
            }
            if (pw!=null) {
                pw.close();
            }
            if (fileWriter!=null) {
                try {
                    fileWriter.close();
                } catch (IOException e) {                   
                }
            }
        }
    }
    
    private void validateNotNull(String name,Object obj) {
        if (obj==null) {
            throw new NullPointerException(name+" is null.");
        }           
    }       
    private void validate(Path directory) throws IOException {          
        File file = directory.toFile();
        if (!file.exists()) {
            throw new IOException("Directory ["+file.getAbsolutePath()+"] do not exists.");
        } else if (!file.isDirectory()) {
            throw new IOException("Directory ["+file.getAbsolutePath()+"] is not a directory.");
        } else if (!file.canRead()) {               
            throw new IOException("Can not read from directory ["+file.getAbsolutePath()+"].");
        } else if (!file.canWrite()) {
            throw new IOException("Can not write to directory ["+file.getAbsolutePath()+"] .");
        }       
    }
    
    private void log(String msg) {
        //TODO
        System.out.println("Task ["+getName()+"] "+msg);
    }
    }
    
    0 讨论(0)
  • 2020-11-29 03:27

    Actually you have incorrectly subscribed to events. Only last listener has been registered with ENTRY_DELETE events type.

    To register for all kind of events at once you should use:

     path.register(service, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE); 
    
    0 讨论(0)
  • 2020-11-29 03:29

    Check this Code...

    https://github.com/omkar9999/FileWatcherHandler

    This project allows watching files for different file events like create, modify & delete and then act on these events in a generic way.

    How to Use?
    Create a Path object representing the directory to monitor for file events.

    Path path = Paths.get("/home/omkar/test");
    

    Implement the FileHandler interface to perform an action detected by file event registered.

    public class FileHandlerTest implements FileHandler {
    
        private static final Logger LOGGER = Logger.getLogger(FileHandlerTest.class.getName());
    
        /*
         * This implemented method will delete the file
         * 
         * @see com.io.util.FileHandler#handle(java.io.File,
         * java.nio.file.WatchEvent.Kind)
         */
        public void handle(File file, Kind<?> fileEvent) {
            LOGGER.log(Level.INFO,"Handler is triggered for file {0}",file.getPath());
            if(fileEvent == StandardWatchEventKinds.ENTRY_CREATE) {
                try {
                    boolean deleted = Files.deleteIfExists(Paths.get(file.getPath()));
                    assertTrue(deleted);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
    }
    

    Create an instance of an Implemented FileHandler

    FileHandlerTest fileHandlerTest = new FileHandlerTest();
    

    Create an instance of a FileWatcher by passing path, an instance of an Implemented FileHandler, and types of file events that you want to monitor separated by commas.

    FileWatcher fileWatcher = new FileWatcher(path, fileHandlerTest, StandardWatchEventKinds.ENTRY_CREATE);
    

    Now Create and start a new Thread.

    Thread watcherThread = new Thread(fileWatcher);
    watcherThread.start();
    

    This thread will start polling for your registered file events and will invoke your custom handle method once any of the registered events are detected.

    0 讨论(0)
  • 2020-11-29 03:33

    Warning! Shameless self promotion!

    I have created a wrapper around Java 1.7's WatchService that allows registering a directory and any number of glob patterns. This class will take care of the filtering and only emit events you are interested in.

    DirectoryWatchService watchService = new SimpleDirectoryWatchService(); // May throw
    watchService.register( // May throw
            new DirectoryWatchService.OnFileChangeListener() {
                @Override
                public void onFileCreate(String filePath) {
                    // File created
                }
    
                @Override
                public void onFileModify(String filePath) {
                    // File modified
                }
    
                @Override
                public void onFileDelete(String filePath) {
                    // File deleted
                }
            },
            <directory>, // Directory to watch
            <file-glob-pattern-1>, // E.g. "*.log"
            <file-glob-pattern-2>, // E.g. "input-?.txt"
            ... // As many patterns as you like
    );
    
    watchService.start();
    

    Complete code is in this repo.

    0 讨论(0)
提交回复
热议问题