前言
最近接到个简单的需求:实时监控文件夹,把新增的文件传到对应的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;
}
本文介绍如何使用Java的WatchService实现对文件夹的实时监控,包括文件的新增、修改和删除,并通过线程池管理和上传到FTP。文章详细讲解了监控文件内容变化、新增文件以及上传文件的代码实现。
452

被折叠的 条评论
为什么被折叠?



