深入 JAVA 系列之 NIO2 文件事件通知
本期议题
- 传统文件事件通知
- NIO2 文件事件通知
-
JVM 文件事件通知实现(Windows 为例)
- NIO1
@since 1.4
- NIO2
@since 1.7
- AIO
@since 1.7
传统文件事件通知
需求:
如何监听一个文件或者文件夹被修改了?
JVM 是以 C++ 为主,也有汇编代码,也有 c
1
2
3
4
5
6
7
private static void println() {
File file = new File("");
out.println("[用户工作目录]: " + file.getAbsolutePath());
// 用户目录,用户工作目录
out.println("[用户目录]:" + System.getProperty("user.home"));
out.println("[用户工作目录]: " + System.getProperty("user.dir"));
}
1
2
3
[用户工作目录]: D:\GuPao_IDEA_xiaomage_workspace\GP-public\nio2-file-event
[用户目录]:C:\Users\Darian
[用户工作目录]: D:\GuPao_IDEA_xiaomage_workspace\GP-public\nio2-file-event
java.io.File
1
2
3
4
5
6
7
8
9
private static final FileSystem fs = DefaultFileSystem.getFileSystem();
public File(String pathname) {
if (pathname == null) {
throw new NullPointerException();
}
this.path = fs.normalize(pathname);
this.prefixLength = fs.prefixLength(this.path);
}
FileSystem
有多种实现
java.io.WinNTFileSystem
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class WinNTFileSystem extends FileSystem {
private final char slash;
private final char altSlash;
private final char semicolon;
public WinNTFileSystem() {
slash = AccessController.doPrivileged(
new GetPropertyAction("file.separator")).charAt(0);
semicolon = AccessController.doPrivileged(
new GetPropertyAction("path.separator")).charAt(0);
altSlash = (this.slash == '\\') ? '/' : '\\';
}
//。。。
}
我们现在的 Windows 操作系统都是在 NT 内核上写出来的。New Technology
新技术。
文件分隔符,都是取得 properties
这是操作系统,JVM 来设置的。
当你的 Tomcat 部署一个应用的时候,jar 包有两个,偶尔出现 类找不到的问题。
1
2
D:\anzhuanga\Java\jdk1.8.0_121\bin\java.exe "-javaagent:D:\anzhuang\IntelliJ IDEA 2018.1.4\lib\idea_rt.jar=3568:D:\anzhuang\IntelliJ IDEA 2018.1.4\bin" -Dfile.encoding=UTF-8 -classpath D:\anzhuanga\Java\jdk1.8.0_121\jre\lib\charsets.jar;D:\anzhuanga\Java\jdk1.8.0_121\jre\lib\deploy.jar;D:\anzhuanga\Java\jdk1.8.0_121\jre\lib\ext\access-bridge-64.jar;D:\anzhuanga\Java\jdk1.8.0_121\jre\lib\ext\cldrdata.jar;D:\anzhuanga\Java\jdk1.8.0_121\jre\lib\ext\dnsns.jar;D:\anzhuanga\Java\jdk1.8.0_121\jre\lib\ext\jaccess.jar;D:\anzhuanga\Java\jdk1.8.0_121\jre\lib\ext\jfxrt.jar;D:\anzhuanga\Java\jdk1.8.0_121\jre\lib\ext\localedata.jar;D:\anzhuanga\Java\jdk1.8.0_121\jre\lib\ext\nashorn.jar;D:\anzhuanga\Java\jdk1.8.0_121\jre\lib\ext\sunec.jar;D:\anzhuanga\Java\jdk1.8.0_121\jre\lib\ext\sunjce_provider.jar;D:\anzhuanga\Java\jdk1.8.0_121\jre\lib\ext\sunmscapi.jar;D:\anzhuanga\Java\jdk1.8.0_121\jre\lib\ext\sunpkcs11.jar;D:\anzhuanga\Java\jdk1.8.0_121\jre\lib\ext\zipfs.jar;D:\anzhuanga\Java\jdk1.8.0_121\jre\lib\javaws.jar;D:\anzhuanga\Java\jdk1.8.0_121\jre\lib\jce.jar;D:\anzhuanga\Java\jdk1.8.0_121\jre\lib\jfr.jar;D:\anzhuanga\Java\jdk1.8.0_121\jre\lib\jfxswt.jar;D:\anzhuanga\Java\jdk1.8.0_121\jre\lib\jsse.jar;D:\anzhuanga\Java\jdk1.8.0_121\jre\lib\management-agent.jar;D:\anzhuanga\Java\jdk1.8.0_121\jre\lib\plugin.jar;D:\anzhuanga\Java\jdk1.8.0_121\jre\lib\resources.jar;D:\anzhuanga\Java\jdk1.8.0_121\jre\lib\rt.jar;D:\GuPao_IDEA_xiaomage_workspace\GP-public\nio2-file-event\target\classes com.darian.io.file.monitor.FileMonitoring
D:\GuPao_IDEA_xiaomage_workspace\GP-public\nio2-file-event
运行日志 -classpath
这里的目录有一定的顺序,不同的操作系统的顺序不太一样。所以有的时候,有的类会找不到。
FileWatchDog
- 单线程
- 多线程
当你有层次性的时候,
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
public class FileMonitoring {
public static void main(String[] args) throws IOException, InterruptedException {
File userDir = new File(System.getProperty("user.dir"));
long lastModified = userDir.lastModified();
List<String> subFiles = list(userDir.list());
while (true) {
// 文件最后的修改事件
if (lastModified == userDir.lastModified()) {
continue;
}
// 保存一份现有的文件
List<String> newSubFiles = list(userDir.list());
// 1. 增加文件
// newSubFiles.removeAll(subFiles); // 剩余的文件
List<String> finalSubFiles = subFiles;
newSubFiles.stream()
.filter(s -> !finalSubFiles.contains(s))
.forEach(value -> out.println("新增的文件:" + value));
finalSubFiles.stream()
.filter(s -> !newSubFiles.contains(s))
.forEach(value -> out.println("删除的文件:" + value));
lastModified = userDir.lastModified();
subFiles = list(userDir.list());
}
}
private static <T> List<T> list(T... values) {
return new ArrayList<>(Arrays.asList(values));
}
private static void println() {
File file = new File("");
out.println("[用户工作目录]: " + file.getAbsolutePath());
// 用户目录,用户工作目录
out.println("[用户目录]:" + System.getProperty("user.home"));
out.println("[用户工作目录]: " + System.getProperty("user.dir"));
}
}
1
2
新增的文件:aaa
删除的文件:aaa
mercyblitz : JDK 1.6 JDK 1.7
实现是否递归的调用。
可读可写的方法是否一样。更改以后,更改时间没有变
1
程序部署在对方的机器上。对方可能 JDK 6 ,也可能 JDK 1.7 ,也可能 JDK 1.5 ,根据对方 版本号,自动选用对用的版本的代码。
接口不变,实现的方式不同。
1
当 `pom.xml` 修改的时候,你会发现 maven 的依赖也修改了,其实我们 `.idea` 包里边也做了变化,idea 也做了监听。
文件事件类型
- 创建
- 修改
- 删除
- 异常
文件 API
File
NIO2 文件事件通知
文件事件类型
- 创建:
StandardWatchEventKinds.ENTRY_CREATE
- 修改:
StandardWatchEventKinds.ENTRY_MODIFY
- 删除:
StandardWatchEventKinds.ENTRY_DELETE
- 异常:
StandardWatchEventKinds.OVERFLOW
文件API
- 服务
WatchService
- 事件
WatchEvent
java.nio.channels.SelectableChannel
1
2
public abstract SelectionKey register(Selector sel, int ops, Object att)
throws ClosedChannelException;
和 NIO 里边的 channel 差不多。
JVM 文件事件通知实现(Windows 为例)
理解 Windows ReadDirectoryChangW
函数
JVM 源码下载
https://download.java.net/openjdk/jdk8