springboot 之 實時監控文件夾變化


spring boot項目配置文件夾監聽器

啟動類上添加@WebListener注解支持

@SpringBootApplication
@ServletComponentScan
public class FileApplication {

    public static void main(String[] args) {
        SpringApplication.run(FileApplication.class, args);
    }
}

通過@WebListener注解開啟監聽

@WebListener
@Slf4j
public class ContextListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        final File file = new File("D:\\test");
        new Thread(() -> {
            try {
                new WatchDir(file, true, new FileActionCallback(){});
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
        log.info("正在監視文件夾:" + file.getAbsolutePath());
    }
}

核心監控類

@Slf4j
public class WatchDir {

    private final WatchService watcher;
    private final Map<WatchKey, Path> keys;
    private final boolean subDir;

    /**
     * 構造方法
     * @param file 文件目錄,不可以是文件
     */
    public WatchDir(File file, boolean subDir, FileActionCallback callback) throws Exception {
        if (!file.isDirectory()) {
            throw new Exception(file.getAbsolutePath() + "不是文件夾!");
        }
        this.watcher = FileSystems.getDefault().newWatchService();
        this.keys = new HashMap<>();
        this.subDir = subDir;

        Path dir = Paths.get(file.getAbsolutePath());

        if (subDir) {
            registerAll(dir);
        } else {
            register(dir);
        }
        processEvents(callback);
    }

    static <T> WatchEvent<T> cast(WatchEvent<?> event) {
        return (WatchEvent<T>) event;
    }

    /**
     * 觀察指定的目錄
     */
    private void register(Path dir) throws IOException {
        WatchKey key = dir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY);
        keys.put(key, dir);
    }

    /**
     * 觀察指定的目錄,並且包括子目錄
     */
    private void registerAll(final Path start) throws IOException {
        Files.walkFileTree(start, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                register(dir);
                return FileVisitResult.CONTINUE;
            }
        });
    }

    /**
     * 發生文件變化的回調函數
     */
    void processEvents(FileActionCallback callback) {
        for (;;) {
            WatchKey key;
            try {
                key = watcher.take();
            } catch (InterruptedException x) {
                return;
            }
            Path dir = keys.get(key);
            if (dir == null) {
               log.error("操作未識別");
                continue;
            }

            for (WatchEvent<?> event : key.pollEvents()) {
                WatchEvent.Kind kind = event.kind();
                // 事件可能丟失或遺棄
                if (kind == StandardWatchEventKinds.OVERFLOW) {
                    continue;
                }
                // 目錄內的變化可能是文件或者目錄
                WatchEvent<Path> ev = cast(event);
                Path name = ev.context();
                Path child = dir.resolve(name);
                File file = child.toFile();
                if (kind.name().equals(StandardWatchEventKinds.ENTRY_DELETE.name())) {
                    callback.delete(file);
                } else if (kind.name().equals(StandardWatchEventKinds.ENTRY_CREATE.name())) {
                    callback.create(file);
                } else if (kind.name().equals(StandardWatchEventKinds.ENTRY_MODIFY.name())) {
                    callback.modify(file);
                } else {
                    continue;
                }

                if (subDir && (kind == StandardWatchEventKinds.ENTRY_CREATE)) {
                    if (Files.isDirectory(child, NOFOLLOW_LINKS)) {
                        try {
                            registerAll(child);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }

            boolean valid = key.reset();
            if (!valid) {
                // 移除不可訪問的目錄
                // 因為有可能目錄被移除,就會無法訪問
                keys.remove(key);
                // 如果待監控的目錄都不存在了,就中斷執行
                if (keys.isEmpty()) {
                    break;
                }
            }
        }
    }
}

創建文件監控回調

@Slf4j
public class FileActionCallback {

    public void delete(File file) {
        log.info("文件已刪除\t" + file.getAbsolutePath());
    }

    public void modify(File file) {
       log.info("文件已修改\t" + file.getAbsolutePath());
    }

    public void create(File file) {
        log.info("文件已創建\t" + file.getAbsolutePath());
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM