SDK1.7新增的nio WatchService能完美解决这个问题。美中不足是如果部署在window系统下会出现莫名其妙的文件夹占用异常导致子目录监听失效,linux下则完美运行。这个问题着实让人头疼。如果有童鞋找到问题根源请一起探讨。

这里简单的列出用Servlet实现的基本类供大家参考。首先是核心的实现类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package com.event;
 
import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
import static java.nio.file.StandardWatchEventKinds.OVERFLOW;
 
import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.WatchEvent;
import java.nio.file.WatchEvent.Kind;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Observable;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
 
import org.apache.poi.ss.formula.ptg.Ptg;
 
public class DirectoryWatcher extends Observable {
// 存储监听主键和监听目录的对应
private static Map<WatchKey, String> pathMap = null;
private WatchService watcher;// 目录监听服务
private WatchKey key;// 目录对应的监听key
private Executor executor = Executors.newSingleThreadExecutor();
FutureTask<Integer> task = new FutureTask<Integer>(() -> {
processEvents();
return Integer.valueOf(0);
});
 
@SuppressWarnings("unchecked")
static <T> WatchEvent<T> cast(WatchEvent<?> event) {
return (WatchEvent<T>) event;
}
 
public DirectoryWatcher(String dir) throws IOException {
watcher = FileSystems.getDefault().newWatchService();
pathMap = new HashMap<WatchKey, String>();
registDirs(dir);
}
 
private void registDirs(String dir) throws IOException {
List<File> dirs = new ArrayList<File>();
File dirRoot = new File(dir);
getAllDirs(dirRoot, dirs);
// 循环路径下所有目录填充map
for (File eveDir : dirs) {
Path path = Paths.get(eveDir.getAbsolutePath());
// 监控目录内文件的更新、创建和删除事件
try {
key = path.register(watcher, ENTRY_CREATE, ENTRY_DELETE);
pathMap.put(key, eveDir.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
}
}
 
// 递归获取所有目录
private void getAllDirs(File dir, List<File> dirs) {
if (dir.isDirectory()) {
dirs.add(dir);
File[] fs = dir.listFiles();
for (File f : fs) {
getAllDirs(f, dirs);
}
}
}
 
/**
* 启动监控过程
*/
public void execute() {
// 通过线程池启动一个额外的线程加载Watching过程
executor.execute(task);
}
 
/**
* 关闭后的对象无法重新启动
*/
public void shutdown() throws IOException {
watcher.close();
executor = null;
}
 
// * 监控文件系统事件
void processEvents() {
while (true) {
// 等待直到获得事件信号
WatchKey signal;
try {
signal = watcher.take();
} catch (InterruptedException x) {
return;
}
for (WatchEvent<?> event : signal.pollEvents()) {
Kind<?> kind = event.kind();
if (kind == OVERFLOW) {
continue;
}
WatchEvent<Path> ev = cast(event);
 
Path name = ev.context();
String fileName = name.getFileName().toString();
String dirPath = pathMap.get(signal) + "/" + fileName;
if (kind.name().equals("ENTRY_CREATE")
&& fileName.indexOf(".") == -1) {
Path path = Paths.get(dirPath);
try {
key = path
.register(watcher, ENTRY_CREATE, ENTRY_DELETE);
pathMap.put(key, dirPath);
} catch (IOException e) {
e.printStackTrace();
}
} else if (kind.name().equals("ENTRY_DELETE")
&& fileName.indexOf(".") == -1) {
pathMap.remove(key);
key.cancel();
}
 
System.out.println("event:" + kind.name() + ";file:" + dirPath);
FileWatchEventArgs args = new FileWatchEventArgs(kind.name(),
pathMap.get(signal), fileName);
notifiy(args);// 通知所有观察者事件变更
}
// 为监控下一个通知做准备
signal.reset();
}
}
 
// * 通知外部各个Observer目录有新的事件更新
void notifiy(FileWatchEventArgs args) {
// 标注目录已经被做了更改
setChanged();
// 主动通知各个观察者目标对象状态的变更
notifyObservers(args);
}
}
来自CODE的代码片
DirectoryWatcher.java

Servlet的实现类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package com.demo;
 
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import com.entry.VedioFile;
import com.event.DirectoryWatcher;
import com.event.FileWatchEventArgs;
 
public class GetList extends HttpServlet implements Observer {
 
private static final long serialVersionUID = 3715567236188574915L;
private String PATH;
private String JsonTreeStr = null;
private static List<VedioFile> vedioFileList;
private static ThreadLocal<String> SubRequestURL = new ThreadLocal<String>();
 
public static ThreadLocal<String> getSubRequestURL() {
return SubRequestURL;
}
 
public static List<VedioFile> getVedioFileList() {
return vedioFileList;
}
 
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PATH = request.getServletContext().getRealPath("/") + "/curse";
 
request.getRequestDispatcher("/WEB-INF/index.jsp").forward(request,
response);
}
 
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
if (vedioFileList == null) {
PATH = request.getServletContext().getRealPath("/") + "curse";
System.out.println(PATH);
setVedioFileList();
// 建立目录监听,注册观察者为本身
DirectoryWatcher dw = new DirectoryWatcher(PATH);
dw.addObserver(this);
dw.execute();
}
 
SubRequestURL
.set(request.getRequestURL().toString().split("getList")[0]);
JsonTreeStr = vedioFileList.toString();
response.setContentType("text/xml;charset=utf-8");
response.setHeader("Cache-Control", "no-cache");
response.getWriter().write(JsonTreeStr);
}
 
@Override
// 实现Observer观察者接口,接收通知
public void update(Observable o, Object arg) {
FileWatchEventArgs args = (FileWatchEventArgs) arg;
 
String name = args.getName();
String kind = args.getKind();
String dir = args.getDir();
 
File file = new File(dir + File.separator + name);
if (kind.equals("ENTRY_CREATE")) {
addVedioFile(file);
} else if (kind.equals("ENTRY_DELETE")) {
removeVedioFile(file);
}
 
}
 
private void removeVedioFile(File file) {
VedioFile nowVf = getNowVedioFile(file);
if (nowVf != null) {
for (int i = vedioFileList.size() - 1; i >= 0; i--) {
if (nowVf.getPath()
.equals(vedioFileList.get(i).getParentPath())) {
vedioFileList.remove(i);
}
}
vedioFileList.remove(nowVf);
}
}
 
private VedioFile getNowVedioFile(File file) {
VedioFile nowVf = null;
for (VedioFile vf : vedioFileList) {
if (file.getAbsolutePath().equals(vf.getPath())) {
nowVf = vf;
break;
}
}
return nowVf;
}
 
private void setVedioFileList() {
File file = new File(PATH);
vedioFileList = new ArrayList<VedioFile>();
getVedioFiles(file, vedioFileList);
}
 
private void getVedioFiles(File file, List<VedioFile> vfs) {
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) {
getVedioFiles(f, vfs);
}
}
addVedioFile(file);
}
 
private void addVedioFile(File file) {
VedioFile vf = new VedioFile();
vf.setParentPath(file.getParent());
vf.setPath(file.getAbsolutePath());
vf.setName(file.getName());
if (file.getName().toLowerCase().endsWith(".mp4")) {
vf.setUrl("vedio?url=" + MD5Utils.md5(vf.getPath()));
}
vedioFileList.add(vf);
}
}
来自CODE的代码片
GetList.java
 转:http://blog.csdn.net/feiying2j/article/details/50719648
附上源码下载地址:
http://download.csdn.net/detail/feiying2j/9439698

Java实现系统目录实时监听更新。的更多相关文章

  1. java实时监听日志写入kafka(转)

    原文链接:http://www.sjsjw.com/kf_cloud/article/020376ABA013802.asp 目的 实时监听某目录下的日志文件,如有新文件切换到新文件,并同步写入kaf ...

  2. java实时监听日志写入kafka(多目录)

    目的 实时监听多个目录下的日志文件,如有新文件切换到新文件,并同步写入kafka,同时记录日志文件的行位置,以应对进程异常退出,能从上次的文件位置开始读取(考虑到效率,这里是每100条记一次,可调整) ...

  3. java实时监听日志写入kafka

    目的 实时监听某目录下的日志文件,如有新文件切换到新文件,并同步写入kafka,同时记录日志文件的行位置,以应对进程异常退出,能从上次的文件位置开始读取(考虑到效率,这里是每100条记一次,可调整) ...

  4. js 实时监听input中值变化

    注意:用到了jquery需要引入jquery.min.js. 需求: 1.每个地方需要分别打分,总分为100; 2.第一个打分总分为40; 3.第二个打分总分为60. 注意:需要判断null.&quo ...

  5. Android实时监听网络状态

    Android实时监听网络状态(1)   其实手机在网络方面的的监听也比较重要,有时候我们必须实时监控这个程序的实时网络状态,android在网络断开与连接的时候都会发出广播,我们通过接收系统的广播就 ...

  6. Android几行代码实现实时监听微信聊天

    实现效果: 实时监听当前聊天页面的最新一条消息,如图:            实现原理: 同样是利用AccessibilityService辅助服务,关于这个服务类还不了解的同学可以先看下我上一篇关于 ...

  7. 移动端用js与jquery实时监听输入框值的改动

    背景: 在一次移动端H5开发中,需要监听输入框值的实时变动. onchange事件肯定抛弃,因为只能失去焦点才触发. 而keyPress在Android可以触发,iOS不可以. 又不想用Android ...

  8. javascript --- 实时监听输入框值的变化

    实时监听文本框值变化是非常常见的功能,通常最简单的办法就是用keyup,keydown来实现,但是这种方法有两个问题,一个是当直接复制粘贴的时候没法监听到事件,另外一个问题是在移动端,使用删除键删除输 ...

  9. 实时监听输入框值变化的完美方案:oninput & onpropertychange

    实时监听输入框值变化的完美方案:oninput & onpropertychange: 网址:http://www.cnblogs.com/lhb25/archive/2012/11/30/o ...

随机推荐

  1. [转]QT 4.8 静态库编译方法

    最最初踏上QT之路是受到了XiaomaGee的指点,相比于常规的窗口程序开发,QT有着以下特点: 1. 优良的跨平台特性(支持Win.Linux.Mac 不同的平台下只需重新编译即可使用) 2. 面向 ...

  2. JavaScript精简代码 非一般的写法(转载)

    摘要:最近在编写一个前端模块功能,编写了大量的代码,其中一般图片特效展示是参考别人的代码来写的,发现有些代码似乎看得明白又好像不确定是不是哪个意思,所以在网上问了一下程序员们,原来是JS代码简写. 转 ...

  3. tomcat的相关使用

    tomcat服务器是apache下非常优秀的一款web服务器,当今的互联网企业中90%左右的中小型企业使用的都是tomcat.tomcat在部署项目时有很多很多的解决方案,这些你都清楚吗? 1.同一个 ...

  4. 使用 Satis 搭建私有的 Composer 包仓库

    简述 iBrand 产品立项时是商业性质的项目,但是在搭建架构时考虑后续的通用性,因此每个模块都设计成一个 Package,作为公司内部用,因此这些包并不能提交到 packagist.org 上去. ...

  5. centos命令行常用操作

    1.查看某个端口占用 lsof -i tcp:80 2.查看是否安装了防火墙 service iptables status 查看是否启用防火墙/etc/init.d/iptables status ...

  6. Linux远程桌面(二)

    上一篇远程桌面采用的独立服务配置不适用于过多用户,这一篇采用超级Internet服务器搭建vnc服务可以解决多用户问题.  vnc之xinetd服务搭建配置 Linux远程桌面(一):vnc之独立服务 ...

  7. 使用ABAP和JavaScript代码生成PDF文件的几种方式

    ABAP 方法1:使用ABAP + Adobe Lifecycle Enterprise Service 详细步骤参考我的博客Convert word document into PDF via Ad ...

  8. MYSQL 之SET GLOBAL innodb_buffer_pool_size =n

    工作遇到一个情况是索引相同的情况下,mysql服务在linux上运行很快,在windows服务器上运行很慢,版本是V5.7以后得版本,同事查找了下说应该设置 SET GLOBAL innodb_buf ...

  9. 45. 腾讯面试题: 使用hashmap 插入数据,怎么样依照插入数据的顺序输出数据

    题目:使用hashmap 插入数据,怎么样依照插入数据的顺序输出数据 分析: 使用hashmap插入数据,数据的顺序会改变.能够写个小程序试试. 那怎么样依照插入的顺序输出呢? 方法一: 这是我第一时 ...

  10. AJAX(二):HTTP头部信息

    每个http请求和响应都会带有相应都头部信息,其中有的对开发人员有用,有的页没有什么用默认情况下,发送xhr请求的同时,还有发送下列头部信息 Accept:浏览器能够处理的内容类型 Accept-Ch ...