Java实现系统目录实时监听更新。

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

时间: 2024-08-01 06:32:44

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

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

原文链接:http://www.sjsjw.com/kf_cloud/article/020376ABA013802.asp 目的 实时监听某目录下的日志文件,如有新文件切换到新文件,并同步写入kafka,同时记录日志文件的行位置,以应对进程异常退出,能从上次的文件位置开始读取(考虑到效率,这里是每100条记一次,可调整) 源码: import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File;

java实时监听日志写入kafka

目的 实时监听某目录下的日志文件,如有新文件切换到新文件,并同步写入kafka,同时记录日志文件的行位置,以应对进程异常退出,能从上次的文件位置开始读取(考虑到效率,这里是每100条记一次,可调整) 源码: [java] view plain copy import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import j

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

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

Rsync+Inotify实时监听备份

说明,下面的inotify是建立在rsync的配置过程 大前提是rsync daemon 配置成功,rsync配置看上一遍博文,在客户端可以推拉数据,然后才能配置inotify服务----inotify是在客户端安装,监听需要备份的目录,然后推送到服务端 查看当前系统是否支持inotify [[email protected] bier]# uname -r 2.6.32-431.el6.i686 [[email protected] bier]# ls -l /proc/sys/fs/inot

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

背景: 在一次移动端H5开发中,需要监听输入框值的实时变动. onchange事件肯定抛弃,因为只能失去焦点才触发. 而keyPress在Android可以触发,iOS不可以. 又不想用Android和iOS都可以触发的keyDown和keyUp. 于是,百度出了新东西:oninput![需要配合propertychange,兼容 IE9 以下版本] 用法: JS: if(isIE) { document.getElementById("input").onpropertychange

js/jquery 实时监听输入框值变化的完美方案:oninput &amp; onpropertychange

本文转载于 http://blog.163.com/lgh_2002/blog/static/44017526201341511112874/ Jquery绑定事件(bind和live的区别) js/jquery 实时监听输入框值变化的完美方案:oninput & onpropertychange js/jquery 实时监听输入框值变化的完美方案:oninput & onpropertychange 2013-05-15 11:01:12|  分类: jquery/javascrip |

js 实时监听input中值变化

js 实时监听input中值变化 分类: Javascript2014-05-11 11:13 849人阅读 评论(0) 收藏 举报 [html] view plaincopyprint? <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>RunJS

socket + pcntl_fork 实现客户端请求,服务器实时监听返回处理 消息推送

<?php /* socket链接整个过程 1,socket_create 第一个参数指定应用程序使用的通信协议的协议族,对于TCP/IP协议族,该参数置AF_INET: 第二个参数指定要创建的套接字类型,流套接字类型为SOCK_STREAM.数据报套接字类型为SOCK_DGRAM.原始套接字SOCK_RAW(WinSock接口并不适用某种特定的协议去封装它,而是由程序自行处理数据包以及协议首部): 第三个参数指定应用程序所使用的通信协议.此参数可以指定单个协议系列中的不同传输协议.在Inter

Android开发之使用BroadcastReceiver实时监听电量(源代码分享)

Android系统中实时的监听手机电量以及开机启动功能都是通过BroadcastReceiver组件实现的.我们可以动态注册这个类的一个实例通过Context.registerReceiver()方法或者静态注册,通过<Receiver>标记在androidmanifest . xml.注意:如果我们注册一个接收器在Activity.onResume()实现,我们应该注销Activity在Activity生命周期的onPause方法中.(这将减少不必要的系统开销).切记不能注销Activity