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. CommonJS 的实现原理

    CommonJS 使用 Node.js 的四个环境变量moduleexportsrequireglobal 只要能够提供这四个变量,浏览器就能加载 CommonJS 模块. Browserify 是目 ...

  2. Saw a tweet from Andrew Liam Trask, sounds like Oxford DeepNLP 2017 class have all videos slides practicals all up. Thanks Andrew for the tip!

    Saw a tweet from Andrew Liam Trask, sounds like Oxford DeepNLP 2017 class have all videos/slides/pra ...

  3. 【转】run方法与start方法的区别

    在java线程中 start与run的不同start与run方法的主要区别在于当程序调用start方法一个新线程将会被创建,并且在run方法中的代码将会在新线程上运行,然而在你直接调用run方法的时候 ...

  4. Html : 规范html代码的网站

    html代码的规范也是很重要的,这里推荐一个网站,很好用,仓鼠是经常用的啦! https://htmlformatter.com/ 以上

  5. C语言总结的知识点

    什么是有效数字? ------------------------- 数据类型 运算符: 函数: 程序结构: 存储结构 内存管理 关键字: ------------------------- C语言: ...

  6. java ——String , StringBuffer, StringBuilder类

    一.String类概述 1.String对象一旦创建就不能改变. 2.字符串常量池. 字符串常量池的特点:池中有则直接使用,池中没有则创建新的字符串常量. 例1: “==”  比较两个对象是否引用同一 ...

  7. Selenium入门8 js调用

    execute_script 可以执行js和jquery脚本 示例如下:修改百度首页的按钮字体颜色,按钮隐藏,按钮显示 #coding=utf-8 # 调用js jquery from seleniu ...

  8. 【HHHOJ】ZJOI2019模拟赛(十四)03.12 解题报告

    点此进入比赛 得分: \(50+5+24=79\) 排名: \(Rank\ 2\) \(Rating\):\(+79\) \(T1\):[HHHOJ197]古明地(点此看题面) 基本上全部时间都用来想 ...

  9. 2016 Al-Baath University Training Camp Contest-1

    2016 Al-Baath University Training Camp Contest-1 A题:http://codeforces.com/gym/101028/problem/A 题意:比赛 ...

  10. http协议的发展历史

    在最早的时候,第一个定稿的http协议是http/0.9版本,在这个版本里面,http协议,它的内容,非常非常的简单 只有一个命令,就是GET 对应的就是我们现在经常用到的get请求,post请求,这 ...