首先说下需求:通过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监听器配置文件监控监听器  

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:root-context.xml</param-value>
</context-param> <filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping> <filter>
<filter-name>sitemesh</filter-name>
<filter-class>com.opensymphony.sitemesh.webapp.SiteMeshFilter</filter-class>
</filter> <filter-mapping>
<filter-name>sitemesh</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping> <servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet> <servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping> <!-- 配置spring监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 配置监控文件变化监听器 -->
<listener>
<listener-class>com.zealer.ad.listener.ThreadStartUpListenser</listener-class>
</listener>
<listener>
<listener-class>com.zealer.ad.listener.SessionLifecycleListener</listener-class>
</listener> <jsp-config>
<taglib>
<taglib-uri>/tag</taglib-uri>
<taglib-location>/WEB-INF/tag/tag.tld</taglib-location>
</taglib>
</jsp-config> <welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list> <session-config>
<session-timeout>45</session-timeout>
</session-config>
</web-app>

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

  ThreadStartUpListenser.java

package com.zealer.ad.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component; import com.zealer.ad.task.WatchFilePathTask; @Component
public class ThreadStartUpListenser implements ServletContextListener
{
private static WatchFilePathTask r = new WatchFilePathTask(); private Log log = LogFactory.getLog(ThreadStartUpListenser.class); /*
* tomcat启动的时候创建一个线程
* */
@Override
public void contextInitialized(ServletContextEvent paramServletContextEvent)
{
r.start();
log.info("ImportUserFromFileTask is started!");
} /*
* tomcat关闭的时候销毁这个线程
* */
@Override
public void contextDestroyed(ServletContextEvent paramServletContextEvent)
{
r.interrupt();
} }

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

    WatchFilePathTask.java

package com.zealer.ad.task;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.joda.time.DateTime; import com.zealer.ad.util.ConfigUtils;
import com.zealer.ad.util.SpringUtils;
/**
* 指定目录文件变化监控类
* @author cancer
*
*/
public class WatchFilePathTask extends Thread
{
private Log log = LogFactory.getLog(WatchFilePathTask.class); private static final String filePath = ConfigUtils.getInstance().getValue("userfile_path"); private WatchService watchService; @Override
public void run()
{
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 = new File(filePath);
//启动时检查是否有未解析的符合要求的文件
if(existFiles.isDirectory())
{
File[] matchFile = existFiles.listFiles(new FileFilter()
{ @Override
public boolean accept(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);
}
}
}

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

package com.zealer.ad.task;

import com.zealer.ad.entity.AutoPutUser;
import com.zealer.ad.entity.Bmsuser;
import com.zealer.ad.service.AutoPutUserService; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.joda.time.DateTime; import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader; import java.util.Date; import javax.annotation.Resource; /**
* 解析用户文件及入库线程,由WatchFilePathTask启动
* @author cancer
*
*/
public class ImportUserFromFileTask extends Thread {
private Log log = LogFactory.getLog(ImportUserFromFileTask.class);
private String fileName;
@Resource(name = "autoPutUserService")
private AutoPutUserService autoPutUserService; @Override
public void run() {
File file = new File(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 = new BufferedReader(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 = new Bmsuser();
bmsuser.setName(lines[0]);if (!"".equals(lines[1])) {
bmsuser.setCity(lines[1]);
}
            //根据唯一索引已经存在的数据则不插入
f = autoPutUserService.insertIgnore(bmsuser); if (f) {
count++;
}
} //汇总数据
AutoPutUser autoPutUser = new AutoPutUser();
autoPutUser.setTotalCount(autoPutUserService.getUserCount());
autoPutUser.setCount(count);
autoPutUser.setCountDate(new Date(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");
}
} public String getFileName() {
return fileName;
} public void setFileName(String fileName) {
this.fileName = fileName;
} public AutoPutUserService getAutoPutUserService() {
return autoPutUserService;
} public void setAutoPutUserService(AutoPutUserService autoPutUserService) {
this.autoPutUserService = autoPutUserService;
}
}

附带:

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

'张三', '深圳'

java利用WatchService实时监控某个目录下的文件变化并按行解析(注:附源代码)的更多相关文章

  1. rsync+inotify 实现资源服务器的同步目录下的文件变化时,备份服务器的同步目录更新,以资源服务器为准,去同步其他客户端

    测试环境: 资源服务器(主服务器):192.168.200.95 备份服务器(客户端):192.168.200.89 同步目录:/etc/test 同步时使用的用户名hadoop密码12345 实验目 ...

  2. 利用WatchService监控C盘根目录下的文件情况

    public static void main(String[] args) throws IOException, InterruptedException { WatchService watch ...

  3. 使用WatchService监控指定目录内的文件的改动

    package coin; import java.io.IOException; import java.nio.file.FileSystems; import java.nio.file.Pat ...

  4. Java中删除文件、删除目录及目录下所有文件(转)

    原文链接:Java中删除文件.删除目录及目录下所有文件 知识点:File.delete()用于删除“某个文件或者空目录”!所以要删除某个目录及其中的所有文件和子目录,要进行递归删除,具体代码示例如下: ...

  5. Java递归列出目录下全部文件

    Java递归列出目录下全部文件 /** * 列出指定目录的全部内容 * */ import java.io.*; class hello{ public static void main(String ...

  6. [Java] 在 jar 文件中读取 resources 目录下的文件

    注意两点: 1. 将资源目录添加到 build path,确保该目录下的文件被拷贝到 jar 文件中. 2. jar 内部的东西,可以当作 stream 来读取,但不应该当作 file 来读取. 例子 ...

  7. Java精选笔记_IO流【File(文件)类、遍历目录下的文件、删除文件及目录】

    File(文件)类 File类用于封装一个路径,该路径可以是从系统盘符开始的绝对路径,也可以是相对于当前目录而言的相对路径 File类内部封装的路径可以指向一个文件,也可以指向一个目录,在使用File ...

  8. [Erlang27]如何监控指定目录下的*.beam文件,如果有改动就更新到指定的节点?

    在Erlang In Anger第二章中讲到使用rebar来创建一个Erlang项目(Application或Project) 但美中不足的只是给出了指引,但没有给出详细的步骤. 下面我们就使用reb ...

  9. Java遍历目录下全部文件并替换指定字符串

    应用场景:比方有一个深层次的文件目录结构,如:javaAPI 每一个文件中面都有同样的内容,而我们要统一改动为其它内容.上千个文件假设一个个改动显得太不明智. import java.io.Buffe ...

随机推荐

  1. MySQL最常用数值函数

    数值函数: 用来处理很多数值方面的运算,使用数值函数,可以免去很多繁杂的判断求值的过程,能够大大提高用户的工作效率. 1.ABS(x):返回 x 的绝对值 mysql> select abs(- ...

  2. java复习(3)---字符串、数组

    String有很多方法,复习一下,把一些很少用的稍微过遍手,加强记忆,方便以后工程上直接使用 (1)length() 返回长度 (2)indexOf() 返回字符串中字符的下标  如:s.indexO ...

  3. Spring事务执行过程

    先说一下启动过程中的几个点: 加载配置文件: AbstractAutowireCapableBeanFactory.doCreateBean --> initializeBean --> ...

  4. MAC系统操作指令汇总

    OSX 的文件系统 OSX 采用的Unix文件系统,所有文件都挂在跟目录 / 下面,所以不在要有Windows 下的盘符概念. 你在桌面上看到的硬盘都挂在 /Volumes 下. 比如接上个叫做 US ...

  5. 用Pyton玩转数据练习题---第二周

    找前5个默尼森数.P是素数且M也是素数,并且满足等式M=2**P-1,则称M为默尼森数.例如,P=5,M=2**P-1=31,5和31都是素数,因此31是默尼森数. # coding:utf-8 im ...

  6. 转-Tomcat 8 安装和配置、优化

    https://github.com/judasn/Linux-Tutorial/blob/master/Tomcat-Install-And-Settings.md Tomcat 8 安装 Tomc ...

  7. J2EE struts2MVC应用在线书签1

    序:之前花了一天研究了一下filter,虽然是实现了MVC模式开发了 WebBookmark,但是代码过于冗长,集中在filter中使用if语句不易阅读,为了体现两份作业的不同点,我决定学习 Java ...

  8. 详解全站 HTTPS 访问优化

    HTTPS 协议就是 HTTP+SSL/TLS,即在 HTTP 基础上加入 SSL /TLS 层,提供了内容加密.身份认证和数据完整性3大功能,目的就是为了加密数据,用于安全的数据传输. HTTPS ...

  9. 图论算法-Dijkstra

    原理 Dijkstra是一个神奇的最短路径算法,它的优点在于它可以稳定的时间内求出一张图从某点到另一点的距离.它的工作原理非常简单,思路类似于广搜.在搜索前,将每个点的颜色设为白色,第一次将源点Ins ...

  10. 576. Out of Boundary Paths

    Problem statement: There is an m by n grid with a ball. Given the start coordinate (i,j) of the ball ...