Java WatchService 监控本地文件夹文件变动

以下demo 可以监控D:\demo 及其子目录下的文件变动(增删改查)
我是尝试用它监控本地报文,但是在多线程往这个文件夹写入文件的时候
watchservice会发生漏扫描的情况,漏掉的往往是每个线程创建的第一个文件。

监控类:

package com.example.watchservice;

import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashMap;
import java.util.Map;

public class TestWatchService {

    private final WatchService watcher;
    private final Map<WatchKey, Path> keys; //所有监控的目录,和监控他们的key
    private volatile int n = 0;
    /**
     * 创建一个 WatchService 并注册给定的目录
     */
    TestWatchService(Path dir) throws IOException {
        this.watcher = FileSystems.getDefault().newWatchService();
        this.keys = new HashMap<WatchKey, Path>();

        walkAndRegisterDirectories(dir);
    }

    /**
     * 使用 WatchService 注册给定的目录;这个函数会被 FileVisitor 调用
     */
    private void registerDirectory(Path dir) throws IOException
    {
        //监控文件,事件为增删改
        WatchKey key = dir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE,StandardWatchEventKinds. ENTRY_MODIFY);
        keys.put(key, dir);
    }

    /**
     * 使用 WatchService 注册给定目录及其所有子目录。
     */
    private void walkAndRegisterDirectories(final Path start) throws IOException {
        // 注册目录和子目录
        Files.walkFileTree(start, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                registerDirectory(dir);
                return FileVisitResult.CONTINUE;
            }
        });
    }

    /**
     * 处理排队等待观察者的键的所有事件
     */
    void processEvents() {
        for (int enterTimes = 0; ;enterTimes++) {

            // wait for key to be signalled
            WatchKey key;
            try {
                key = watcher.take();
            } catch (InterruptedException x) {
                return;
            }

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

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

                // 目录条目事件的上下文是条目的文件名
                @SuppressWarnings("unchecked")
                Path name = ((WatchEvent<Path>)event).context();
                Path child = dir.resolve(name);
                
                System.out.format("EnterTimes:%5d %s->No %-5d: %s\n",enterTimes, event.kind().name(),++n, child);
                
                if (kind == StandardWatchEventKinds.ENTRY_CREATE) {
                    try {
                        if (Files.isDirectory(child)) { // 如果目录已创建,并递归查看,则注册它及其子目录
                            walkAndRegisterDirectories(child);
                        }
                    } catch (IOException x) {
                        // do something useful
                    }
                }
            }

            // 如果目录不再可访问,则重置密钥并从集合中删除
            boolean valid = key.reset();
            if (!valid) {
                keys.remove(key);

                // 所有目录都无法访问
                if (keys.isEmpty()) {
                    break;
                }
            }
        }
    }

    public static void main(String[] args) throws IOException {
        Path dir = Paths.get("D:\\demo");
        new TestWatchService(dir).processEvents();
    }

}

文件创建类:

public class FileCreator {

    /**
     * 启动多线程创建文件
     * @param args
     */
    public static void main(String[] args) {
        final String rootPath = "D:\\IdeaProjects\\MESSAGE\\SzjgHTH";
        final int count = 10000;
        final ExecutorService exec = Executors.newFixedThreadPool(4);
        ExecutorService executorService = new ThreadPoolExecutor(3, 100, 5, TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>());
        for (int i = 0; i < count; i++) {
            int finalI = i;
            exec.execute(() -> {
                writeFile("hello",rootPath+"\\hello\\"+ finalI +".txt");
            });
        }
    }

    public static void writeFile(String content, String path) {
        PrintWriter output = null;
        try {
            //判断路径是否存在,不存在则创建
            String abPath = path.substring(0, path.lastIndexOf("\\"));
            File file = new File(abPath);
            mkdirs(file);
            output = new PrintWriter(new OutputStreamWriter(new FileOutputStream(path), StandardCharsets.UTF_8));
            output.println(content);
            output.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    //创建目录
    public static boolean mkdirs(File file){
        boolean success;
        if(!file.exists()){ //不存在 则创建
            if(!file.exists()){
                // 同步 :不存在 则创建
                success = file.mkdirs();
            }else {
                //否则就是已创建
                success = true;
            }
        }else {
            //否则就是已创建
            success = true;
        }
        return success;
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值