Watching a Directory for Changes in Java

前端 未结 6 479
灰色年华
灰色年华 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: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 tasks = new ArrayList();
    
    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 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 fileMonitor = new Hashtable();
    
    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 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) 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 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);
    }
    }
    

提交回复
热议问题