• Java NIO.2 使用Path接口来监听文件、文件夹变化


    Java7对NIO进行了大的改进,新增了许多功能:

    • 对文件系统的访问提供了全面的支持
    • 提供了基于异步Channel的IO

    这些新增的IO功能简称为 NIO.2,依然在java.nio包下。

    早期的Java只提供了File类来操作文件、文件夹本身,功能有限,性能也不高。

    NIO.2为解决这种缺陷,提供了Path接口,并提供了Paths、Files2个工具类,这2个工具类包含的方法都是静态方法,Files类提供了大量的静态方法来操作文件、文件夹。

    Path接口、Paths工具类使用示例:

     1  //获取指定路径的Path对象
     2         Path path=Paths.get("D:/untitled/test/");   
     3         //也可以这样写:   Path path=Paths.get("D","untitled","test");    参数个数可变
     4 
     5         //返回文件/文件夹名,test
     6         System.out.println(path.getFileName());
     7         //返回父目录的路径,D:untitled
     8         System.out.println(path.getParent());
     9         //判断该路径的最后一级是否是指定的文件/文件夹,true。和String的endsWith有点不同。当参数是最后一级的文件/文件夹名时,才返回true。
    10         System.out.println(path.endsWith("test"));    
    11         //以上方法的操作对象是Path对象中的路径,就是说路径不必是真实存在的
    12 
    13         //返回根路径(盘符),D:
    14         System.out.println(path.getRoot());
    15         //返会绝对路径
    16         System.out.println(path.toAbsolutePath());   
    17         //以上获取的路径要是真实存在的

    以前,如果要监控文件、目录的变化(新建、修改、删除),一般是启动一条后台线程,这条线程每隔一段时间去遍历指定目录的文件,如果此次遍历的结果与上次遍历的结果不同,就认为文件发生了变化。这种方式很繁琐,性能也低。

    NIO.2的Path接口提供了一个方法来监听文件变化:

    register(WatchService watcher, 要监听的事件类型1,要监听的事件类型2,.......)       //注册一个监听服务

    比如“xx安全卫士提醒您:xx程序将创建xx文件,是否允许?”、“xx程序试图修改xx文件,是否允许?”,就可使用此方法实现。

    使用示例:

     1 public class Test {
     2     public static void main(String[] args) throws IOException, InterruptedException {
     3 
     4         //创建一个文件系统的监听服务
     5         WatchService watchService= FileSystems.getDefault().newWatchService();
     6 
     7         Path path=Paths.get("D:/untitled/test");
     8         
     9         //为该文件夹注册监听,监听新建、修改、删除事件。只能为文件夹(目录)注册监听,不能为单个文件注册监听
    10         path.register(watchService,StandardWatchEventKinds.ENTRY_CREATE,StandardWatchEventKinds.ENTRY_MODIFY,StandardWatchEventKinds.ENTRY_DELETE);
    11 
    12         //编写事件处理
    13         while (true){  //一直监听
    14             //拉取一个WatchKey。当触发监听的事件时,就会产生一个WatchKey,此WatchKey封装了事件信息。
    15             WatchKey watchKey=watchService.take();
    16 
    17             //使用循环是因为这一个WatchKey中可能有多个文件变化了,比如Ctrl+A全选,然后删除,只触发了一个WatchKey,但有多个文件变化了
    18             for (WatchEvent event:watchKey.pollEvents()){   
    19                 System.out.println(event.context()+"发生了"+event.kind()+"事件!");
    20                 /*
    21                 watchKey.pollEvents()  获取此次WatchKey中所有变化了的文件的信息,以List(列表)形式返回,一个WatchEvent就是一个元素,封装了一个变化了的文件的信息
    22                 event.context()  获取文件名
    23                 event.kind()  获取发生的事件类型
    24 
    25                 因为只能为文件夹注册监听,如果要监听某些指定的文件,可以在增强的for循环中,先根据event.context()判断是否是指定的文件,是才处理。
    26                  */
    27             }
    28 
    29             //虽然是while()循环,但WatchKey和ByteBuffer一样,使用完要重置状态,才能继续用。
    30             watchKey.reset();    //如果不重置,WatchKey使用一次过后就不能再使用,即只能监听到一次文件变化。
    31         }
    32 
    33 
    34         /*
    35         测试:在D:/untitled/test目录下
    36         1、新建1.txt文件      1.txt.txt发生了ENTRY_CREATE事件!
    37         2、打开1.txt,输入"hello world!",并保存      1.txt.txt发生了ENTRY_MODIFY事件!
    38         3、删除“hello world!",并保存      1.txt.txt发生了ENTRY_MODIFY事件!
    39         4、新建2.txt文件    2.txt发生了ENTRY_CREATE事件!
    40 
    41         说明:编辑文件内容时,不算修改,保存时才算修改。
    42 
    43         5、新建文件夹“图片”
    44             新建文件夹发生了ENTRY_CREATE事件!
    45             新建文件夹发生了ENTRY_DELETE事件!
    46             图片发生了ENTRY_CREATE事件!
    47         OS执行过程:新建了一个名为“新建文件夹”的文件夹,再把此文件夹重命名为指定的名称。
    48         重命名时,”新建文件夹“消失了,算作删除,”图片“出现了,算作新建。
    49 
    50         6、在图片目录下,随便新建一个文件或者文件夹
    51             图片发生了ENTRY_MODIFY事件!
    52          说明监控的只是子文件、子文件夹,不会递归监控。
    53 
    54         7、全选,删除test下所有文件、子文件夹
    55             图片发生了ENTRY_DELETE事件!
    56             1.txt.txt发生了ENTRY_DELETE事件!
    57             2.txt发生了ENTRY_DELETE事件!
    58          */
    59 
    60 
    61     }
    62 }

    拉取一个WatchKey有3种方法:

    • WatchKey  take()   //阻塞式拉取,如果未拉取到,会一直等待,直到拉取到一个WatchKey。一般我们用这个。
    • WatchKey   poll()   //非阻塞式拉取,试图拉取一个WatchKey,拉取到了就返回拉取的WatchKey对象,没有WatchKey发生就立即返回null。
    • WatchKey   poll(long  timeout, TimeUnit  unit)    //非阻塞式拉取,如果没拉取到,会再等待timeout毫秒,还没拉取到才返回null。
  • 相关阅读:
    快速排序(详解)
    14.linux-platform机制实现驱动层分离(详解)
    13.Linux键盘按键驱动 (详解)
    Linux-hexdump命令调试event驱动—详解(13)
    Android开发final的用法
    Android控件RecyclerView的基本用法
    搜索关键词分析——以个人博客网站为例
    java.net.SocketException: Software caused connection abort: socket write error
    Android layout属性大全
    java中 label 配合 break continue 使用方法
  • 原文地址:https://www.cnblogs.com/chy18883701161/p/10941220.html
Copyright © 2020-2023  润新知