Java WatchService监听文件事件 获取的绝对路径与真实路径不匹配
问题原因说明
这不是JDK的bug,是对WatchService API返回值的理解偏差导致的使用错误。WatchEvent.context() 返回的Path对象是相对路径,路径范围仅为被监听目录下的条目名,不包含被监听目录本身的前缀信息。你直接对这个相对路径调用toAbsolutePath()方法时,方法默认会以JVM启动时的工作目录(系统参数user.dir对应的值,你的环境下是/data/myprojects/test1/)作为基准路径做拼接,自然会得到指向程序运行目录的错误路径。
错误代码定位
出错的核心逻辑在事件处理部分:
for (WatchEvent <?> we : wk.pollEvents ()) { Path pc = (Path) we.context (); // 此处pc是仅包含文件名的相对路径,直接转绝对路径会拼接错误的基准目录 System.out.println (" fn=" + pc.getFileName () + " ap=" + pc.toAbsolutePath ()); }
修复方案
解析事件对应文件的真实路径时,必须用你注册监听时使用的目录路径作为父路径,拼接事件返回的相对路径,才能得到正确结果;同时注意处理完事件后需要重置WatchKey,否则无法接收后续事件。
修正后的完整代码如下:
import java.io.*; import java.nio.file.*; import java.util.*; void foo () throws IOException, InterruptedException { String dir = "/tmp/mytest"; WatchService ws = FileSystems.getDefault().newWatchService(); // 保存被监听目录的路径引用,后续解析事件路径需要使用 Path watchedDir = Paths.get(dir); watchedDir.register(ws, StandardWatchEventKinds.ENTRY_CREATE); for (int i = 0; i < 8; i++) { System.out.println ("check " + i); WatchKey wk = ws.poll(); if (wk != null) { for (WatchEvent <?> we : wk.pollEvents()) { Path eventRelativePath = (Path) we.context(); // 用监听目录拼接相对路径,得到文件真实绝对路径 Path realAbsolutePath = watchedDir.resolve(eventRelativePath); System.out.println (" fn=" + eventRelativePath.getFileName() + " ap=" + realAbsolutePath); } // 必须重置WatchKey,才能继续接收后续监听事件 wk.reset(); } if (i == 3) { File f = new File(dir + "/a.txt"); f.createNewFile(); System.out.println ("created " + f.getAbsolutePath()); } Thread.sleep(1000); } }
补充注意事项
你当前的测试代码只创建了一个文件、循环次数少,没有暴露WatchKey未重置的问题。实际使用时如果不调用wk.reset(),第一次触发事件后该WatchKey就不会再上报新的监听事件,会直接导致文件监听功能失效。
内容的提问来源于stack exchange,提问作者chris01
相关产品推荐
相关产品推荐

