重命名目录后,WatchService目录路径不正确



代码注册使用监视服务创建的任何新目录,以侦听所有事件并持续运行60秒[可随运行时间变化]

final class Test 
{
public static void main(String[] args)throws Exception
{
//Run the program for 60 seconds i.e * 1000
long RUNNING_TIME=60*1000;

try(WatchService service=FileSystems.getDefault().newWatchService())
{
//Register test directory for observation
Path.of("E:","Folder A").register(service,StandardWatchEventKinds.ENTRY_CREATE,StandardWatchEventKinds.ENTRY_MODIFY,StandardWatchEventKinds.ENTRY_DELETE);

long start=System.currentTimeMillis();
while(System.currentTimeMillis()-start<RUNNING_TIME)
{
//Use poll not take else while loop will be blocked
WatchKey key=service.poll();

if(key==null){continue;}
for(WatchEvent event:key.pollEvents())
{
//Get the absolute path from the event context by resolving it against it's parent directory
Path
eventPath=(Path)event.context(),
absolutePath=((Path)key.watchable()).resolve(eventPath); //Wrong path after resolving against watchable after renaming directory
Kind kind=event.kind();

//If the event kind is CREATE and an new directory is created then register that directory with the service
if(kind==StandardWatchEventKinds.ENTRY_CREATE && Files.isDirectory(absolutePath))
{
absolutePath.register
(
service,
StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_MODIFY,
StandardWatchEventKinds.ENTRY_DELETE
);
}

//Debugging
System.out.println("Event Path="+eventPath);
System.out.println("Absolute Path="+absolutePath);
System.out.println("Kind="+kind);
System.out.println("==========================");
}

key.reset();
}  
}
}
}

以下是的观察结果

Sno                            Test                                  Output
1       Create Directory=>E:/Folder A/New Folder               Event Path=New folder
Absolute Path=E:Folder ANew folder
Kind=ENTRY_CREATE
==========================

2        Rename E:/Folder A/New Folder                         Event Path=New folder
TO                                 Absolute Path=E:Folder ANew folder
E:/Folder A/Test                           Kind=ENTRY_DELETE
==========================
Event Path=Test
Absolute Path=E:Folder ATest
Kind=ENTRY_CREATE

3        Create Text File Under Test Folder i.e            Event Path=New Text Document.txt
Create => E:/Folder A/Test/New Text Document.txt     Absolute Path=E:Folder ANew folderNew Text Document.txt
Kind=ENTRY_CREATE
==========================
Event Path=Test
Absolute Path=E:Folder ATest
Kind=ENTRY_MODIFY


4    Rename  E:/Folder A/Test/New Text Document.txt        Event Path=New Text Document.txt
To                                 Absolute Path=E:Folder ANew folderNew Text Document.txt
E:/Folder A/Test/Test.txt                      Kind=ENTRY_DELETE
==========================
Event Path=Test.txt
Absolute Path=E:Folder ANew folderTest.txt
Kind=ENTRY_CREATE                                                          
==========================
Event Path=Test
Absolute Path=E:Folder ATest
Kind=ENTRY_MODIFY

绝对路径中的测试用例3出现错误结果以下是从测试用例3开始的错误绝对路径值

Absolute Path=E:Folder ANew folderNew Text Document.txt
Absolute Path=E:Folder ANew folderTest.txt

正如你所看到的,在测试用例2中,我已经从"要测试的新文件夹"重命名了我的文件夹,那么为什么它在解析可监视目录时仍然出现。

很明显,错误出现在watchable((返回的Path中,或者我应该在重命名或其他情况下取消此键以获得正确的结果。

为什么watchable((方法在重命名目录后没有返回正确的路径?

如果为重命名的目录注销以前的监视设置,可以避免此问题。重命名时,您会得到父文件夹监视的DELETE,然后是CREATE,因此您可以修改监视的目录以取消旧密钥,并注册新密钥。

以下是您的主要内容,其中包括记录使用中的密钥以及使用HashMap处理删除+创建以跟踪添加到监视服务的目录的小调整:

var keys = new HashMap<Path,WatchKey>();
try (WatchService service = FileSystems.getDefault().newWatchService()) {
// Register test directory for observation
Path root = Path.of("C:/Temp/Folder A");
WatchKey wk = root.register(service, StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE);
System.out.println("ROOT register=" + root +" wk="+wk);
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < RUNNING_TIME) {
// Use poll not take else while loop will be blocked
WatchKey key = service.poll();
if (key == null) {
continue;
}
for (var event : key.pollEvents())  {
// Get the absolute path from the event context by resolving it against it's
// parent directory
Path eventPath = (Path) event.context(), absolutePath = ((Path) key.watchable()).resolve(eventPath);
var kind = event.kind();
// Debugging
System.out.println("==========================");
System.out.println("Watch Key=" + key);
System.out.println("Event Path=" + eventPath);
System.out.println("Absolute Path=" + absolutePath);
System.out.println("Kind=" + kind);
// If the event kind is CREATE and an new directory is created then register
// that directory with the service
if (kind == StandardWatchEventKinds.ENTRY_CREATE && Files.isDirectory(absolutePath)) {
var subkey = absolutePath.register(service, StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE);
keys.put(absolutePath, subkey);
System.out.println("register=" + absolutePath +" wk="+subkey);
}
// Deletes: wipe previously registered watch
else if (kind == StandardWatchEventKinds.ENTRY_DELETE) {
var prev = keys.remove(absolutePath);
if (prev != null) {
System.out.println("unregister=" + absolutePath + " key="+prev);
prev.cancel();
}
}
}
key.reset();
}
}

从上面开始,然后创建";子文件夹";将报告三个不同的手表键:

ROOT register=C:TempFolder A wk=... $WindowsWatchKey@aaaaaaaaa
Watch Key=... $WindowsWatchKey@aaaaaaaaa
Kind=ENTRY_CREATE
register=C:TempFolder Asubfolder wk=... $WindowsWatchKey@xxxxxxxx

重命名";子文件夹";至";"最新";说:

Watch Key=... $WindowsWatchKey@aaaaaaaaa
Kind=ENTRY_DELETE
unregister=C:TempFolder Asubfolder key=... $WindowsWatchKey@xxxxxxxx
Watch Key=... $WindowsWatchKey@aaaaaaaaa
Kind=ENTRY_CREATE
register=C:TempFolder ALATEST wk=... $WindowsWatchKey@yyyyyyyyy

然后,在新目录名下编辑文件将使用当前文件夹名进行报告,最重要的是,使用重命名后的新监视键,而不是之前打印的@xxxxxxxx值:

Watch Key=sun.nio.fs.WindowsWatchService$WindowsWatchKey@yyyyyyyyy
Event Path=file.txt
Absolute Path=C:TempFolder ALATESTfile.txt
Kind=ENTRY_MODIFY