java监听目录或者文件的变化
2021/9/9 22:35:13
本文主要是介绍java监听目录或者文件的变化,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
一、场景
我们可能需要监听目录或者文件的变化,做出相应操作。
比如 配置文件变化后,需要重新加载配置。
二、Java监听目录变化的实现方式
参考:
https://zq99299.github.io/java-tutorial/essential/io/notification.html#watch-%E6%9C%8D%E5%8A%A1%E6%A6%82%E8%BF%B0
三、注意事项
1、监听的事件发生时,java应用程序不会实时感知到,而是有一定的间隔。监听程序默认10s检测一次。
代码:
PollingWatchService.java // enables periodic polling void enable(Set<? extends WatchEvent.Kind<?>> events, long period) { synchronized (this) { // update the events this.events = events; // create the periodic task Runnable thunk = new Runnable() { public void run() { poll(); }}; this.poller = scheduledExecutor .scheduleAtFixedRate(thunk, period, period, TimeUnit.SECONDS); } } SensitivityWatchEventModifier.java public enum SensitivityWatchEventModifier implements Modifier { /** * High sensitivity. */ HIGH(2), /** * Medium sensitivity. */ MEDIUM(10), /** * Low sensitivity. */ LOW(30); /** * Returns the sensitivity in seconds. */ public int sensitivityValueInSeconds() { return sensitivity; } private final int sensitivity; private SensitivityWatchEventModifier(int sensitivity) { this.sensitivity = sensitivity; } }
2、监听的修改事件发生时,文件不一定被修改完成。实际上内容flush到文件时,就会触发修改事件。因此有可能读到不完整的文件内容。
证据1:WatchService的注释中写道:
When an event is reported to indicate that a file in a watched
directory has been modified then there is no guarantee that the
program (or programs) that have modified the file have completed. Care
should be taken to coordinate access with other programs that may be
updating the file. The FileChannel class defines methods to lock
regions of a file against access by other programs.
证据2:
下述代码验证
四、代码示例和验证
import com.sun.nio.file.SensitivityWatchEventModifier; import java.io.*; import java.nio.file.*; import java.util.Date; public class WatchFileDemo { public static void main(String[] args) { String dir = "/tmp/"; new Thread(() -> { watchFile(dir); }).start(); String file1 = dir + "xx.json"; testWriteFile1(file1); String file2 = dir + "yy.json"; testWriteFile2(file2); } public static void watchFile(String dir) { try (WatchService watchService = FileSystems.getDefault().newWatchService()){ Path path = Paths.get(dir); //注册文件 创建、修改 事件的监听 path.register(watchService, new WatchEvent.Kind[]{StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY}, SensitivityWatchEventModifier.HIGH); while (true) { //返回排队的 key。如果没有排队的密钥可用,则此方法等待。 WatchKey key = watchService.take(); for (WatchEvent<?> watchEvent : key.pollEvents()) { WatchEvent.Kind<?> kind = watchEvent.kind(); WatchEvent<Path> watchEventPath = (WatchEvent<Path>) watchEvent; //检索与事件关联的文件名。文件名被存储为事件的上下文 Path filename = watchEventPath.context(); System.out.println(new Date() + " 文件:" + filename + ",发生事件:" + kind.name()); //无论注册了什么事件,都可能收到一个 OVERFLOW 事件(表名事件被丢失或者丢弃),可以处理或则忽略 if (kind == StandardWatchEventKinds.OVERFLOW) { continue; } else if (kind == StandardWatchEventKinds.ENTRY_CREATE) { System.out.println(filename + "被创建"); // System.out.println(readFile(dir + filename.toString())); } else if (kind == StandardWatchEventKinds.ENTRY_MODIFY) { System.out.println(filename + "被修改"); // System.out.println(readFile(dir + filename.toString())); } } //在处理完事件后,需要通过 reset() 将事件重置 ready 状态。 //如果此方法返回false,则该 key 不再有效,循环可以退出。 boolean valid = key.reset(); if (!valid) { break; } } } catch (IOException | InterruptedException e) { e.printStackTrace(); } } /** * 只写。等到最后再保存 * @param filename */ public static void testWriteFile1(String filename) { System.out.println(new Date() + ":开始写,test1"); try { FileWriter writer = new FileWriter(filename); // BufferedWriter writer = new BufferedWriter(new FileWriter(filename)); for (int i=0; i< 10; i++) { Thread.sleep(5000); writer.write("test1\n"); System.out.println(new Date() + ":写test1"); } writer.close(); } catch (IOException | InterruptedException e) { e.printStackTrace(); } System.out.println(new Date() + ":写完毕,test1"); } /** * 写的时候每次都flush * @param filename */ public static void testWriteFile2(String filename) { System.out.println(new Date() + ":开始写,test2"); try { FileWriter writer = new FileWriter(filename); // BufferedWriter writer = new BufferedWriter(); for (int i=0; i< 10; i++) { Thread.sleep(5000); writer.write("test2\n"); writer.flush(); System.out.println(new Date() + ":写test2"); } writer.close(); } catch (IOException | InterruptedException e) { e.printStackTrace(); } System.out.println(new Date() + ":写完毕,test2"); } public static String readFile(String filename) { try (BufferedReader reader = new BufferedReader(new FileReader(filename));){ String line; StringBuilder result = new StringBuilder(); while ((line = reader.readLine()) != null) { result.append(line).append(System.lineSeparator()); } return result.toString(); } catch (IOException e) { e.printStackTrace(); } return null; } }
执行结果:
Thu Sep 09 17:29:59 CST 2021:开始写,test1
Thu Sep 09 17:30:01 CST 2021 文件:xx.json,发生事件:ENTRY_MODIFY
xx.json被修改
Thu Sep 09 17:30:04 CST 2021:写test1
Thu Sep 09 17:30:09 CST 2021:写test1
Thu Sep 09 17:30:14 CST 2021:写test1
Thu Sep 09 17:30:19 CST 2021:写test1
Thu Sep 09 17:30:24 CST 2021:写test1
Thu Sep 09 17:30:29 CST 2021:写test1
Thu Sep 09 17:30:34 CST 2021:写test1
Thu Sep 09 17:30:39 CST 2021:写test1
Thu Sep 09 17:30:44 CST 2021:写test1
Thu Sep 09 17:30:49 CST 2021:写test1
Thu Sep 09 17:30:49 CST 2021:写完毕,test1
Thu Sep 09 17:30:49 CST 2021:开始写,test2
Thu Sep 09 17:30:51 CST 2021 文件:xx.json,发生事件:ENTRY_MODIFY
xx.json被修改
Thu Sep 09 17:30:51 CST 2021 文件:yy.json,发生事件:ENTRY_MODIFY
yy.json被修改
Thu Sep 09 17:30:54 CST 2021:写test2
Thu Sep 09 17:30:55 CST 2021 文件:yy.json,发生事件:ENTRY_MODIFY
yy.json被修改
Thu Sep 09 17:30:59 CST 2021:写test2
Thu Sep 09 17:31:01 CST 2021 文件:yy.json,发生事件:ENTRY_MODIFY
yy.json被修改
Thu Sep 09 17:31:04 CST 2021:写test2
Thu Sep 09 17:31:05 CST 2021 文件:yy.json,发生事件:ENTRY_MODIFY
yy.json被修改
Thu Sep 09 17:31:09 CST 2021:写test2
Thu Sep 09 17:31:11 CST 2021 文件:yy.json,发生事件:ENTRY_MODIFY
yy.json被修改
Thu Sep 09 17:31:14 CST 2021:写test2
Thu Sep 09 17:31:15 CST 2021 文件:yy.json,发生事件:ENTRY_MODIFY
yy.json被修改
Thu Sep 09 17:31:19 CST 2021:写test2
Thu Sep 09 17:31:21 CST 2021 文件:yy.json,发生事件:ENTRY_MODIFY
yy.json被修改
Thu Sep 09 17:31:24 CST 2021:写test2
Thu Sep 09 17:31:25 CST 2021 文件:yy.json,发生事件:ENTRY_MODIFY
yy.json被修改
Thu Sep 09 17:31:29 CST 2021:写test2
Thu Sep 09 17:31:31 CST 2021 文件:yy.json,发生事件:ENTRY_MODIFY
yy.json被修改
Thu Sep 09 17:31:34 CST 2021:写test2
Thu Sep 09 17:31:35 CST 2021 文件:yy.json,发生事件:ENTRY_MODIFY
yy.json被修改
Thu Sep 09 17:31:39 CST 2021:写test2
Thu Sep 09 17:31:39 CST 2021:写完毕,test2
Thu Sep 09 17:31:41 CST 2021 文件:yy.json,发生事件:ENTRY_MODIFY
yy.json被修改
可以看到测试1每次write不一定被检测到修改事件,测试2每次write后都调用flush函数,就可以每次都检测到修改事件。
这篇关于java监听目录或者文件的变化的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-01后台管理开发学习:新手入门指南
- 2024-11-01后台管理系统开发学习:新手入门教程
- 2024-11-01后台开发学习:从入门到实践的简单教程
- 2024-11-01后台综合解决方案学习:从入门到初级实战教程
- 2024-11-01接口模块封装学习入门教程
- 2024-11-01请求动作封装学习:新手入门教程
- 2024-11-01登录鉴权入门:新手必读指南
- 2024-11-01动态面包屑入门:轻松掌握导航设计技巧
- 2024-11-01动态权限入门:新手必读指南
- 2024-11-01动态主题处理入门:新手必读指南