WatchService:文件新增,修改的实时监控

前言

最近接到个简单的需求:实时监控文件夹,把新增的文件传到对应的ftp,要求监控的文件夹可实时配置,使用jline提供人机交互接口进行文件的重传.略一思考,WatchService可以实现实时监控需求.

WatchService是jdk1.7提供的类,基于操作系统的文件系统监控器,实现对文件新增,修改,删除的监控功能,详细的说明可以自行百度.

思路

1.系统启动,加载配置文件,为每个配置项提供一个监控器,当有文件新增,上传到对应的ftp

2.系统启动,监控配置文件,当配置文件内容发生变化,为每个新增的配置项提供监控器

3.WatchService监控会阻塞线程,使用线程池管理线程

4.由于文件较大,需要考虑文件还在传输程序就进行上传和上传是否成功的问题

代码实现

贴出关键的方法代码,仅供参考

线程配置类

@Configuration
public class PoolConfig {
    @Bean
    public Executor pool() {
        ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor();
        threadPool.setCorePoolSize(6); //核心线程数
        threadPool.setMaxPoolSize(100);//最大线程数
        threadPool.setKeepAliveSeconds(3000);//线程最大空闲时间
        threadPool.setQueueCapacity(100);//队列
        threadPool.setThreadNamePrefix("file-upload-");//线程名称前缀
        //拒绝策略
        threadPool.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //初始化线程池,不然报错
        threadPool.initialize();
        return threadPool;
    }
}

监控文件内容变化

Path path = Paths.get(configFilePath);//configFilePath是文件夹
WatchService watchService = FileSystems.getDefault().newWatchService();
//监听文件夹路径下的文件内容发生改变
path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
while (true) {
    WatchKey wk = watchService.take();//阻塞
    for (WatchEvent<?> event : wk.pollEvents()) {
        Path changed = (Path) event.context();
        Path absolute = path.resolve(changed);
        //发生内容变化的文件
        File configFile = absolute.toFile();
        if (configFileName.equals(configFile.getName())) {
            long lastModified = configFile.lastModified();
            // 利用文件时间戳,防止触发两次
            if (lastModified != configFileModifiedTime && configFile.length() > 0) {
                log.info("文件{}发生内容变化", configFile);
                configFileModifiedTime = lastModified;
                addDirWatch(configFile);
            }
        }
    }
    // 必须重置WatchKey,否则无法监控下次变化
    if (!wk.reset()) {
        log.error("重置WatchKey异常");
    }
}

记录配置文件的上一次修改的时间与当前修改时间对比,防止触发2次.

监控文件新增

WatchService watchService = FileSystems.getDefault().newWatchService();
//监听新增
Paths.get(dirPath).register(watchService, StandardWatchEventKinds.ENTRY_CREATE);
while (true) {
    //没有文件增加时,阻塞在这里
    WatchKey key = watchService.take();
    for (WatchEvent<?> event : key.pollEvents()) {
        File file = new File(dirPath, event.context().toString());
        log.info("增加文件是" + file.getAbsolutePath());
        if (file.getName().endsWith(".ZIP") && !uploadService.getAlreadyUploadFiles().contains(file.getName())) {
            //等待文件传输完成
            FileUtil.waitForFileTransfer(file.getAbsolutePath(),100L);
            uploadService.uploadAndWriter(removePath, file, "上传");
        }
    }
    if (!key.reset()) {
        break;
    }
}

每次上传成功需要记录,防止重传

等待文件传输完成

public static void waitForFileTransfer(String filePath,long waitTime) {
    try {
        File file = new File(filePath);
        long len1, len2;
        len2 = file.length();
        do {
            len1 = len2;
            Thread.sleep(waitTime);
            file = new File(filePath);
            len2 = file.length();
        } while (len1 < len2);
    } catch (Exception e) {
        log.error("文件传输失败", e);
    }
}

检查是否上传成功

上传前记录文件大小==上传后获取ftp文件大小,上传成功

public static booleangetFtpFileSize(String host, int port,String username, String password, String remotePath, String fileName,long size) {
    FTPClient ftp = new FTPClient();
    long fileSize = 0L;
    boolean flag = false;
    try {
        //登录
        if (!login(ftp, host, port, username, password)) {
            log.error("登陆ftp失败");
        }
        try {
            //进入目录
            ftp.changeWorkingDirectory(remotePath);
        } catch (Exception e) {
            log.info("进入远程目录{}失败,case:[{}]", remotePath, e);
        }
        //遍历
        for (FTPFile file : ftp.listFiles()) {
            if (file.getName().equals(fileName)){
                log.info("成功找到文件{}", fileName);
                if(size == file.getSize()){
                   flag = true
                }
                break;
            }
        }
        
    } catch (Exception e) {
        log.error("操作ftp发生异常{}", e);
    } finally {
        try {
            //退出ftp
            ftp.logout();
            //关闭FTP
            if (ftp.isConnected()) {
                ftp.disconnect();
            }
        } catch (IOException e) {
            log.error("关闭ftp发生异常[{}]", e);
        }
    }
    return flag;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值