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. spring-cloud构架微服务(1)-全局配置

    使用spring-cloud是基于熟悉springboot基础上进行的.本篇介绍全局配置,spring-boot版本就以1.4.0来做吧.项目地址: https://git.oschina.net/b ...

  2. Socket连接时,端口是怎么分配的

    socket 客户端连接socket 的端口每个是唯一的,每个新的连接,端口号+1 从1024-65534 最大到65534 然后再开始循环 中间遇到已经使用的端口就跳过

  3. PHP 简单调用rest WebServices

    <?php $ch = curl_init("http://api.cachk.com:8185/Tech-Trans.esPOS4.PosService.UAT/rest/enqui ...

  4. react+webpack 引入字体图标

    在使用react+webpack 构建项目过程中免不了要用到字体图标,在引入过程中报错,不能识别字体图标文件中的@符,报错 Uncaught Error: Module parse failed: U ...

  5. Wampserver由橙变绿的解决过程

    因为C盘的内存问题,就重装了win7系统,那么就面临着很对软件要重新进行安装,安装wampserver时,再次遇到了服务器的图标一直是橙色的而不变绿色,安装包地址: http://download.c ...

  6. anaconda添加源(channels)

    如果使用environment.yml下载conda环境时,系统很慢,那么可以增加其他的下载源: - https://conda.anaconda.org/menpo - https://mirror ...

  7. 转:postMan 使用教程

    转:https://www.cnblogs.com/alanjl/p/5490922.html 自从开始做API开发之后,我就在寻找合适的API测试工具.一开始不是很想用Chrome扩展,用的 Wiz ...

  8. C sharp #003# 面向对象编程基本构件

    饮水思源:金老师的自学网站 索引 类的属性 简化字段/属性的初始化 命名空间 程序集 类的属性 字段+get/set方法=属性 (之前都是把字段和属性混着用..) 经典写法: using System ...

  9. 裁剪插件jCrop

    为大家介绍个插件:jCrop.这个插件被我用在了多个项目中,如通过画热力图来查看某块地方用户的浏览数,放大缩小拖动选框来实时预览所选区域的图片病裁剪,设置头像是选框必须要是正方形,它有着丰富的配置参数 ...

  10. aop 和castle 的一些 学习文章

    https://www.cnblogs.com/zhaogaojian/p/8360363.html