你还在使用定时轮询的方式监听目录下的文件变化吗

你还在使用定时轮询的方式监听目录下的文件变化吗

WatchService

不知道大家监听目录下的文件变化时是否还是在使用轮询的方式去记录、比对文件状态

今天介绍一个接口 WatchService

简单好用

作用

监视注册对象的更改和事件的监视服务。例如,文件管理器可以使用监视服务来监视目录的更改,以便它可以在创建或删除文件时更新其文件列表的显示。

说明

对象Watchable通过调用其方法向监视服务注册register,返回 WatchKey 表示注册。当检测到对象的事件时,会向键发出信号,如果当前未发出信号,则会将其排队到监视服务,以便调用 polltake方法来检索键并处理事件的消费者可以检索它。一旦事件被处理,消费者调用密钥的reset方法来重置密钥,这允许Key被发信号并与进一步的事件重新排队。

通过调用 key 的方法可以取消手表服务的注册 cancel。取消时排队的密钥将保留在队列中,直到被检索。根据对象的不同,可能会自动取消某个键。例如,假设监视一个目录,并且监视服务检测到该目录已被删除或其文件系统不再可访问。当以这种方式取消某个键时,如果当前未发出信号,则会发出信号并排队。为了确保通知消费者,该reset 方法的返回值指示密钥是否有效。

监视服务可供多个并发消费者安全使用。为了确保任何时候只有一个使用者处理特定对象的事件,则应注意确保reset 仅在处理其事件后才调用该键的方法。close可以随时调用该方法来关闭服务,从而导致任何等待检索密钥的线程抛出ClosedWatchServiceException

文件系统报告事件的速度可能比检索或处理事件的速度快,并且实现可能对其可能累积的事件数量施加未指定的限制。如果实现故意 丢弃事件,那么它会安排键的pollEvents方法返回事件类型为 的元素OVERFLOW。消费者可以使用该事件作为触发器来重新检查对象的状态。

当报告事件表明监视目录中的文件已被修改时,不能保证修改该文件的程序已完成。应注意协调与可能更新该文件的其他程序的访问。该类FileChannel定义了锁定文件区域以防止其他程序访问的方法。

show me the code

import java.nio.file.*;
import java.util.concurrent.TimeUnit;

/**
 * @author brucewee
 * @date 2024/1/2 22:25
 */
public class WatchServiceTest {

    public static void main(String[] args) {

        try {
            //声明一个watchservice
            WatchService watchService = FileSystems.getDefault().newWatchService();
            //在要监听的目录上注册watchservice 及要监听的事件
            String dir = "D:\\test";
            Path path = Paths.get(dir);
            if(Files.notExists(path)){
                Files.createDirectory(path);
            }

            path.register(watchService,
                    StandardWatchEventKinds.ENTRY_CREATE,
                    StandardWatchEventKinds.ENTRY_DELETE,
                    StandardWatchEventKinds.ENTRY_MODIFY,
                    StandardWatchEventKinds.OVERFLOW);

            while(true){
                //WatchKey key = watchService.take(); //使用take会一直阻塞 直接该目录下有文件变化
                //poll 可以在指定时间内拿不到就返回
                WatchKey key = watchService.poll(3, TimeUnit.SECONDS);
                if(key != null){
                    //获取监听到的事件
                    for(WatchEvent<?> event : key.pollEvents()){
                        //每个事件进行处理
                        if(event.kind() == StandardWatchEventKinds.ENTRY_CREATE){
                            System.out.println("add " + dir + event.context());
                        }
                        if(event.kind() == StandardWatchEventKinds.ENTRY_DELETE){
                            System.out.println("delete " + dir + event.context());
                        }
                        if(event.kind() == StandardWatchEventKinds.ENTRY_MODIFY){
                            System.out.println("modify " + dir + event.context());
                        }
                        //这种情况有可能监控的文件太多导致溢出
                        if(event.kind() == StandardWatchEventKinds.OVERFLOW){
                            //do something
                        }
                    }
                    //每次监听结束后要重置key
                    key.reset();
                }

                //break condition
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

运行结果

add D:\test新建 文本文档.txt
modify D:\test新建 文本文档.txt
delete D:\test新建 文本文档.txt
  • 12
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个示例代码,实现两个页面之间的定时轮询,同时使用`localStorage`模拟数据存储。在这个示例中,我们假设有两个页面:`PageA`和`PageB`,分别表示轮询数据的页面和获取数据的页面。 PageA.vue: ```html <template> <div> <p>轮询数据:{{ state.data }}</p> <p>数据更新时间:{{ state.updateTime }}</p> </div> </template> <script> import { onMounted, onUnmounted, reactive } from 'vue'; export default { setup() { const state = reactive({ data: null, updateTime: null, intervalId: null, }); const fetchData = () => { // 从localStorage获取数据 const dataFromStorage = localStorage.getItem('data'); const updateTimeFromStorage = localStorage.getItem('updateTime'); state.data = JSON.parse(dataFromStorage); state.updateTime = updateTimeFromStorage; }; onMounted(() => { // 页面加载时启动轮询 state.intervalId = setInterval(fetchData, 5000); }); onUnmounted(() => { // 页面卸载时停止轮询 clearInterval(state.intervalId); }); return { state, }; }, }; </script> ``` 在这个组件中,我们使用`reactive`函数创建了一个响应式的状态对象`state`,其中包含了轮询所需的数据`data`、数据更新时间`updateTime`和计时器的ID`intervalId`。在`fetchData`函数中,我们从`localStorage`中获取数据,并将数据更新到`state.data`和`state.updateTime`中。在`onMounted`钩子函数中,我们使用`setInterval`函数启动轮询,并将计时器的ID保存到`state.intervalId`中。在`onUnmounted`钩子函数中,我们使用`clearInterval`函数停止轮询,以免页面卸载后仍然执行轮询操作。最后,我们将`state`对象暴露出去,以便在模板中访问轮询数据。 PageB.vue: ```html <template> <div> <p>页面B</p> </div> </template> <script> import { onMounted, onUnmounted } from 'vue'; export default { setup() { const updateData = () => { // 生成随机数作为数据 const data = Math.random(); const updateTime = new Date().toLocaleString(); // 将数据写入localStorage localStorage.setItem('data', JSON.stringify(data)); localStorage.setItem('updateTime', updateTime); }; onMounted(() => { // 页面加载时启动定时更新 setInterval(updateData, 10000); }); onUnmounted(() => { // 页面卸载时停止定时更新 clearInterval(); }); }, }; </script> ``` 在这个组件中,我们使用`setInterval`函数定时生成随机数,并将数据写入`localStorage`中。在页面卸载时,我们使用`clearInterval`函数停止定时更新操作。 注意:在实际应用中,我们需要根据具体需求对代码进行修改和优化,例如在数据更新后需要通知其他页面更新数据等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值