WatchService详解

一、WatchService的坑

虽然WatchService是一种极为方便的Java API,但是在使用中也存在一些坑。首先,操作系统的缓存机制可能会导致WatchService监听不到某些事件。其次,WatchService不支持监听远程目录的变化。最后,WatchService可能会轮询事件导致CPU占用率过高。

二、WatchService不能监听远程目录

由于WatchService是基于本地文件系统实现的,因此它不能监听远程目录的变化。如果需要监听远程目录的变化,可以考虑使用SSH、SCP或者FTP等协议实现。

三、WatchService原理

WatchService的原理是通过JNI层来向操作系统注册文件事件,然后通过回调函数将事件传递给Java应用层。当WatchService监控到文件系统上的事件时,会将该事件加入WatchService的事件队列中,然后等待Java应用层调用take()方法来获取事件。

四、WatchService用户组

在使用WatchService时,可以通过创建WatchKey对象并指定其用户组来区分不同的WatchService监听器。例如:

WatchService watchService = FileSystems.getDefault().newWatchService();
Path path = Paths.get("/path/to/listen");
path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY).userData(new Object());

这样就可以在触发事件时通过WatchKey的userData()方法来确定事件是由哪个监听器触发的。

五、WatchService监听不到

在使用WatchService时,可能会出现监听不到某些事件的情况。有以下几种可能的原因:

1、操作系统缓存机制导致WatchService无法监听到某些事件。

2、WatchService内部事件队列满了,还没有被Java层消费。

3、监听器注册的文件没有读权限。

4、某些事件被同时触发,但是WatchService只能获取到一次事件。

5、操作系统或者JVM内存资源不足。

六、WatchService获取全路径

在使用WatchService时,获取文件变化的全路径非常重要。可以通过如下方式获取:

WatchKey watchKey = watchService.take();
for (WatchEvent<?> event : watchKey.pollEvents()) {
    Path path = ((WatchEvent<Path>) event).context();
    Path fullpath = ((Path) watchKey.watchable()).resolve(path); // 获取全路径
...
}

七、WatchService的modify

在使用WatchService监听文件的modify事件时,可能会出现修改多次但只监听到一次的情况。这是因为操作系统会在某个时间段内合并多个修改事件。可以通过在代码中加入时间延迟的方式来解决这个问题。

private long lastModifiedTime = 0L;
private WatchKey watchKey;

while (true) {
    try {
        watchKey = watchService.take();
        for (WatchEvent<?> event : watchKey.pollEvents()) {
            Path path = ((WatchEvent<Path>)event).context();
            Path fullPath = ((Path) watchKey.watchable()).resolve(path);
            if (event.kind() == StandardWatchEventKinds.ENTRY_MODIFY) {
                long currentModifiedTime = Files.getLastModifiedTime(fullPath).toMillis();
                if (currentModifiedTime - lastModifiedTime > 1000) { // 延迟时间为1秒
                    lastModifiedTime = currentModifiedTime;
                    // 处理modify事件
                }
            }
        }
        watchKey.reset();
    } catch (Throwable e) {
        e.printStackTrace();
    }
}

八、WatchService无法监听挂载目录

如果需要监听挂载目录的变化,可以考虑使用JavaNativeAccess(JNA)实现Native监听器,参考代码如下:

interface CLibrary extends Library {
    public class StructStat extends Structure {
        public long st_ino;
        public long st_mode;
        public long st_nlink;
        ...
    }
    CLibrary INSTANCE = (CLibrary) Native.loadLibrary("c", CLibrary.class);

    int statvfs(String path, StructStatvfs buf);
    int stat(String path, StructStat buf);
}

// 监听挂载目录
new Thread(() -> {
    while (true) {
        try {
            Thread.sleep(1000);
            CLibrary.StructStat buf = new CLibrary.StructStat();
            int res = CLibrary.INSTANCE.stat(path, buf);
            if (res == 0) {
                long fsUid = buf.st_dev;
                if (fsUid == expectedFsUid) { // 监听目标文件系统
                    // 监听文件变化
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}).start();

原创文章,作者:OPIJ,如若转载,请注明出处:https://www.506064.com/n/135745.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
OPIJOPIJ
上一篇 2024-10-04 00:14
下一篇 2024-10-04 00:14

相关推荐

  • Linux sync详解

    一、sync概述 sync是Linux中一个非常重要的命令,它可以将文件系统缓存中的内容,强制写入磁盘中。在执行sync之前,所有的文件系统更新将不会立即写入磁盘,而是先缓存在内存…

    编程 2025-04-25
  • 神经网络代码详解

    神经网络作为一种人工智能技术,被广泛应用于语音识别、图像识别、自然语言处理等领域。而神经网络的模型编写,离不开代码。本文将从多个方面详细阐述神经网络模型编写的代码技术。 一、神经网…

    编程 2025-04-25
  • MPU6050工作原理详解

    一、什么是MPU6050 MPU6050是一种六轴惯性传感器,能够同时测量加速度和角速度。它由三个传感器组成:一个三轴加速度计和一个三轴陀螺仪。这个组合提供了非常精细的姿态解算,其…

    编程 2025-04-25
  • Python输入输出详解

    一、文件读写 Python中文件的读写操作是必不可少的基本技能之一。读写文件分别使用open()函数中的’r’和’w’参数,读取文件…

    编程 2025-04-25
  • 详解eclipse设置

    一、安装与基础设置 1、下载eclipse并进行安装。 2、打开eclipse,选择对应的工作空间路径。 File -> Switch Workspace -> [选择…

    编程 2025-04-25
  • git config user.name的详解

    一、为什么要使用git config user.name? git是一个非常流行的分布式版本控制系统,很多程序员都会用到它。在使用git commit提交代码时,需要记录commi…

    编程 2025-04-25
  • nginx与apache应用开发详解

    一、概述 nginx和apache都是常见的web服务器。nginx是一个高性能的反向代理web服务器,将负载均衡和缓存集成在了一起,可以动静分离。apache是一个可扩展的web…

    编程 2025-04-25
  • Java BigDecimal 精度详解

    一、基础概念 Java BigDecimal 是一个用于高精度计算的类。普通的 double 或 float 类型只能精确表示有限的数字,而对于需要高精度计算的场景,BigDeci…

    编程 2025-04-25
  • Linux修改文件名命令详解

    在Linux系统中,修改文件名是一个很常见的操作。Linux提供了多种方式来修改文件名,这篇文章将介绍Linux修改文件名的详细操作。 一、mv命令 mv命令是Linux下的常用命…

    编程 2025-04-25
  • Python安装OS库详解

    一、OS简介 OS库是Python标准库的一部分,它提供了跨平台的操作系统功能,使得Python可以进行文件操作、进程管理、环境变量读取等系统级操作。 OS库中包含了大量的文件和目…

    编程 2025-04-25

发表回复

登录后才能评论