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. Android 通过接口的方式去调用服务里面的方法

    public class MainActivity extends AppCompatActivity { private MyConn conn; private Iservice myBinder ...

  2. 如何解决ArcGIS Runtime SDK for Android中文标注无法显示的问题

    自10.2版本开始,我就一直被ArcGIS Runtime SDK for Android的中文标注无限困扰.无论是驻留于内存中的Graphic 的文本符号TextSymbol,还是新增的离线geod ...

  3. Asp.net防御XSS攻击组件库

    一.AntiXss 翻看mvc4高级编程,偶看到作者强烈推荐使用AntiXss防御XSS攻击,收集资料看下. 目前类库已融入到.netframework中,类库主页不再更新. 使用方法:使用Nuget ...

  4. 运用Hadoop能否搭建完整的云计算平台?

    Apache Hadoop 是一个用java语言实现的软件框架,在由大量计算机组成的集群中运行海量数据的分布式计算,它可以让应用程序支持上千个节点和PB级别的数据. Hadoop并不完全代表云计算,所 ...

  5. IOS GCD03-其他用法

    #define global_queue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) #define main_queu ...

  6. Xcode 自定义控件创建及触发事件

    #pragma mark 控制器的view加载完毕的时候调用 //一般在这里进行界面的初始化 - (void)viewDidLoad { [super viewDidLoad]; NSLog(@&qu ...

  7. Bean的初始化和销毁

    在我们实际开发的时候,经常会遇到在Bean在使用之前或者之后做些必要的操作,Spring对Bean的生命周期的操作提供了支持.在使用Java配置和注解配置下提供如下两种方式.    1.Java配置方 ...

  8. idea中将项目转换成Maven项目

    第一步:项目右键->Add Framework... 选择maven ok 这样就成功转换成了一个maven项目

  9. ZIGBEE report机制分析

    ZIGBEE提供了report机制(现在只学习了send, receive还没学习) 主要目的是实现attribute属性的report功能,即提供了一种服务端和客户端数据同步的机制 以EMBER的H ...

  10. 第42章 电源管理—实现低功耗—零死角玩转STM32-F429系列

    第42章     电源管理—实现低功耗 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fir ...