java 实时监视文件变化_java利用WatchService实时监控某个目录下的文件变化并按行解析...

本文介绍了如何使用Java的WatchService来实时监控文件系统的变化,特别是当有新文件上传到指定目录时,程序能自动读取文件并按行解析,将数据写入数据库。通过创建一个监听器在Tomcat启动时启动后台线程,利用WatchService监控文件创建事件,发现符合要求的文件后,启动新的线程进行文件解析和数据导入。
摘要由CSDN通过智能技术生成

首先说下需求:通过ftp上传约定格式的文件到服务器指定目录下,应用程序能实时监控该目录下文件变化,如果上传的文件格式符合要求,将将按照每一行读取解析再写入到数据库,解析完之后再将文件改名。

一. 一开始的思路

设置一个定时任务,每隔一分钟读取下指定目录下的文件变化,如果有满足格式的文件,就进行解析。

这种方式很繁琐,而且效率低,效率都消耗在了遍历、保存状态、对比状态上了! 而且无法利用OS的很多功能。

二. WatchService介绍

1、 该类的对象就是操作系统原生的文件系统监控器!我们都知道OS自己的文件系统监控器可以监控系统上所有文件的变化,这种监控是无需遍历、无需比较的,是一种基于信号收发的监控,因此效率一定是最高的;现在Java对其进行了包装,可以直接在Java程序    中使用OS的文件系统监控器了;

2、 获取当前OS平台下的文件系统监控器:

i. WatchService watcher = FileSystems.getDefault().newWatchService();

ii. 从FileSystems这个类名就可以看出这肯定是属于OS平台文件系统的,接下来可以看出这一连串方法直接可以得到一个文件监控器;

这里暂时不用深入理解这串方法的具体含义,先知道怎么用就行了;

3、 我们都知道,操作系统上可以同时开启多个监控器,因此在Java程序中也不例外,上面的代码只是获得了一个监控器,你还可以用同样的代码同时获得多个监控器;

4、 监控器其实就是一个后台线程,在后台监控文件变化所发出的信号,这里通过上述代码获得的监控器还只是一个刚刚初始化的线程,连就绪状态都没有进入,只是初始化而已;

三、实现过程

其实就是在初始化的时候创建一个线程,然后用watchService实时监控该目录下文件变化,如果有满足条件文件加进来,就按照约定的格式解析文件再写入数据库,详细步骤如下!

1、web.xml监听器配置文件监控监听器

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

contextConfigLocation

classpath:root-context.xml

CharacterEncodingFilter

org.springframework.web.filter.CharacterEncodingFilter

encoding

UTF-8

forceEncoding

true

CharacterEncodingFilter

/*

sitemesh

com.opensymphony.sitemesh.webapp.SiteMeshFilter

sitemesh

/*

appServlet

org.springframework.web.servlet.DispatcherServlet

contextConfigLocation

classpath:servlet-context.xml

1

appServlet

/

org.springframework.web.context.ContextLoaderListener

com.zealer.ad.listener.ThreadStartUpListenser

com.zealer.ad.listener.SessionLifecycleListener

/tag

/WEB-INF/tag/tag.tld

index.jsp

45

View Code

2、编写一个ThreadStartUpListenser类,实现ServletContextListener,tomcat启动时创建后台线程

ThreadStartUpListenser.java

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

packagecom.zealer.ad.listener;importjavax.servlet.ServletContextEvent;importjavax.servlet.ServletContextListener;importorg.apache.commons.logging.Log;importorg.apache.commons.logging.LogFactory;importorg.springframework.stereotype.Component;importcom.zealer.ad.task.WatchFilePathTask;

@Componentpublic class ThreadStartUpListenser implementsServletContextListener

{private static WatchFilePathTask r = newWatchFilePathTask();private Log log = LogFactory.getLog(ThreadStartUpListenser.class);/** tomcat启动的时候创建一个线程

**/@Overridepublic voidcontextInitialized(ServletContextEvent paramServletContextEvent)

{

r.start();

log.info("ImportUserFromFileTask is started!");

}/** tomcat关闭的时候销毁这个线程

**/@Overridepublic voidcontextDestroyed(ServletContextEvent paramServletContextEvent)

{

r.interrupt();

}

}

View Code

3、创建指定目录文件变化监控类

WatchFilePathTask.java

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

packagecom.zealer.ad.task;importjava.io.File;importjava.io.FileFilter;importjava.io.IOException;importjava.nio.file.FileSystems;importjava.nio.file.Path;importjava.nio.file.StandardWatchEventKinds;importjava.nio.file.WatchEvent;importjava.nio.file.WatchKey;importjava.nio.file.WatchService;importorg.apache.commons.logging.Log;importorg.apache.commons.logging.LogFactory;importorg.joda.time.DateTime;importcom.zealer.ad.util.ConfigUtils;importcom.zealer.ad.util.SpringUtils;/*** 指定目录文件变化监控类

*@authorcancer

**/

public class WatchFilePathTask extendsThread

{private Log log = LogFactory.getLog(WatchFilePathTask.class);private static final String filePath = ConfigUtils.getInstance().getValue("userfile_path");privateWatchService watchService;

@Overridepublic voidrun()

{try{//获取监控服务

watchService =FileSystems.getDefault().newWatchService();

log.debug("获取监控服务"+watchService);

Path path=FileSystems.getDefault().getPath(filePath);

log.debug("@@@:Path:"+path);final String todayFormat = DateTime.now().toString("yyyyMMdd");

File existFiles= newFile(filePath);//启动时检查是否有未解析的符合要求的文件

if(existFiles.isDirectory())

{

File[] matchFile= existFiles.listFiles(newFileFilter()

{

@Overridepublic booleanaccept(File pathname)

{if((todayFormat+".txt").equals(pathname.getName()))

{return true;

}else{return false;

}

}

});if(null !=matchFile)

{for(File file : matchFile)

{//找到符合要求的文件,开始解析

ImportUserFromFileTask task = (ImportUserFromFileTask) SpringUtils.getApplicationContext().getBean("importUserFromFileTask");

task.setFileName(file.getAbsolutePath());

task.start();

}

}

}//注册监控服务,监控新增事件

WatchKey key =path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);while (true) {

key=watchService.take();for (WatchEvent>event : key.pollEvents()) {//获取目录下新增的文件名

String fileName =event.context().toString();//检查文件名是否符合要求

if((todayFormat+".txt").equals(fileName))

{

String filePath= path.toFile().getAbsolutePath()+File.separator+fileName;

log.info("import filePath:"+filePath);//启动线程导入用户数据

ImportUserFromFileTask task = (ImportUserFromFileTask) SpringUtils.getApplicationContext().getBean("importUserFromFileTask");//new ImportUserFromFileTask(filePath);

task.setFileName(filePath);

task.start();

log.debug("启动线程导入用户数据"+task);

}

}

key.reset();

}

}catch(IOException e)

{

log.error(e.getMessage(),e);

}catch(InterruptedException e)

{

log.error(e.getMessage(),e);

}

}

}

View Code

4、创建解析用户文件及导入数据库线程,由WatchFilePathTask启动

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

packagecom.zealer.ad.task;importcom.zealer.ad.entity.AutoPutUser;importcom.zealer.ad.entity.Bmsuser;importcom.zealer.ad.service.AutoPutUserService;importorg.apache.commons.logging.Log;importorg.apache.commons.logging.LogFactory;importorg.joda.time.DateTime;importjava.io.BufferedReader;importjava.io.File;importjava.io.FileInputStream;importjava.io.InputStreamReader;importjava.util.Date;importjavax.annotation.Resource;/*** 解析用户文件及入库线程,由WatchFilePathTask启动

*@authorcancer

**/

public class ImportUserFromFileTask extendsThread {private Log log = LogFactory.getLog(ImportUserFromFileTask.class);privateString fileName;

@Resource(name= "autoPutUserService")privateAutoPutUserService autoPutUserService;

@Overridepublic voidrun() {

File file= newFile(fileName);if (file.exists() &&file.isFile()) {

log.debug(":@@@准备开始休眠10秒钟:" +file);//休眠十分钟,防止文件过大还没完全拷贝到指定目录下,这里的线程就开始读取文件

try{

sleep(10000);

}catch(InterruptedException e1) {

e1.printStackTrace();

}

InputStreamReader read;try{

read= new InputStreamReader(new FileInputStream(file), "UTF-8");

BufferedReader bufferedReader= newBufferedReader(read);

String lineTxt= null;int count = 0;

Boolean f= false;while ((lineTxt = bufferedReader.readLine()) != null) {if ((null == lineTxt) || "".equals(lineTxt)) {continue;

}if (lineTxt.startsWith("'")) {

lineTxt= lineTxt.substring(1, lineTxt.length());

}//解析分隔符为', '

String[] lines = lineTxt.split("', '");int length =lines.length;if (length < 2) {continue;

}

Bmsuser bmsuser= newBmsuser();

bmsuser.setName(lines[0]);if (!"".equals(lines[1])) {

bmsuser.setCity(lines[1]);

}//根据唯一索引已经存在的数据则不插入

f =autoPutUserService.insertIgnore(bmsuser);if(f) {

count++;

}

}//汇总数据

AutoPutUser autoPutUser = newAutoPutUser();

autoPutUser.setTotalCount(autoPutUserService.getUserCount());

autoPutUser.setCount(count);

autoPutUser.setCountDate(newDate(System.currentTimeMillis()));

String today= DateTime.now().toString("yyyy-MM-dd");

Integer oldCount=autoPutUserService.getOldCount(today);//如果今天导入过了就更新否则插入

if (!oldCount.equals(0)) {

autoPutUserService.updateUserData(autoPutUser, today,

oldCount);

}else{

autoPutUserService.gatherUserData(autoPutUser);

}//注意:要关闭流

read.close();

}catch(Exception e) {

log.error(e.getMessage(), e);

}

File newFile= new File(file.getPath() +System.currentTimeMillis()+ ".complate");

file.renameTo(newFile);

}else{

log.error(fileName+ " file is not exists");

}

}publicString getFileName() {returnfileName;

}public voidsetFileName(String fileName) {this.fileName =fileName;

}publicAutoPutUserService getAutoPutUserService() {returnautoPutUserService;

}public voidsetAutoPutUserService(AutoPutUserService autoPutUserService) {this.autoPutUserService =autoPutUserService;

}

}

View Code

附带:

1、sql脚本

CREATE TABLE `bmsuser` (

`id`int(255) unsigned NOT NULL AUTO_INCREMENT,

`name` varchar(32) DEFAULT NULL ,

`city` varchar(32) DEFAULT NULL COMMENT ,

PRIMARY KEY (`bmsid`),

UNIQUE KEY `bbLoginName` (`bbLoginName`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2、文件格式,命名为yyyyMMdd.txt

'张三', '深圳'

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值