欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-04-08 14:55:24
Java7对NIO进行了大的改进,新增了许多功能: 对文件系统的访问提供了全面的支持 提供了基于异步Channel的IO 这些新增的IO功能简称为 NIO.2,依然在java.nio包下。 早期的Java只提供了File类来操作文件、文件夹本身,功能有限,性能也不高。 NIO.2为解决这种缺陷,提供 ......

 

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。