6

当 WatchService 监视的目录被删除时,其父目录不会立即在其 File 的 listFiles 方法中反映删除,因此无法删除。在整个服务被明确停止之前,父级的后果似乎是:

  1. 删除非空目录的推荐递归解决方案失败。
  2. 正常终止时未执行deleteOnExit
  3. 调用删除返回 false 并且对文件系统没有影响。

为了演示,这个测试代码:

import java.io.*;
import java.nio.file.*;

class DirectoryTester { 
  static WatchService watcher; 
  static {
    try{watcher = FileSystems.getDefault().newWatchService();} 
    catch (IOException e) {e.printStackTrace();}
  }

  public static void main(String[] args) throws IOException {
    String SEPARATE = System.getProperty("file.separator");
    String testDirName = System.getProperty("user.dir") + SEPARATE + "testDir";
    String subDirName = testDirName + SEPARATE + "subDir";
    String fileName = subDirName + SEPARATE +"aFile";
    create(fileName);
    Paths.get(subDirName).register(watcher, StandardWatchEventKinds.ENTRY_DELETE);
    delete(new File(testDirName));
  }

  static void create(String nameOfFile) throws IOException {
    new File(nameOfFile).getParentFile().mkdirs();
    Files.createFile(Paths.get(nameOfFile));
    System.out.println("Created " + nameOfFile);
  }     

  static void delete(File toDelete) throws IOException {
    if (toDelete.isDirectory())
      for (File c : toDelete.listFiles()) 
        delete(c);
    int numContainedFiles = toDelete.listFiles() != null ? toDelete.listFiles().length : 0;
    if (!toDelete.delete()) {
      System.out.println("Failed to delete " + toDelete + " containing " + numContainedFiles);
    }
    else {
      System.out.println("Deleted " + toDelete + " containing " + numContainedFiles);
    }
  }  
}

在 windows 上给出以下输出,这对应testDir于文件系统上没有被删除。

Created C:\Dropbox\CodeSpace\JavaTestbed\src\testDir\subDir\aFile
Deleted C:\Dropbox\CodeSpace\JavaTestbed\src\testDir\subDir\aFile containing 0
Deleted C:\Dropbox\CodeSpace\JavaTestbed\src\testDir\subDir containing 0
Failed to delete C:\Dropbox\CodeSpace\JavaTestbed\src\testDir containing 1

如果我在删除后放置一个断点,subDir我可以看到它实际上已在文件系统上被删除。从断点恢复会导致最后一次删除成功,这表明这可能是监视服务线程所做更改的可见性的问题。有谁知道这里发生了什么,如果它是一个错误?我实际上想要做的是删除受监视的目录而不停止对其他目录的监视,因为 API 似乎没有提供取消注册路径方法,还有什么其他标准的 Java 方法可以实现这一点?

4

1 回答 1

7

可能相关:

http://bugs.sun.com/view_bug.do?bug_id=6972833

WatchService 对每个被监视的目录都有一个打开的句柄。如果删除了一个监视目录,则 WatchService 关闭句柄,以便可以从父目录中删除目录条目。期望能够立即删除父目录的实用程序和应用程序会出现问题,因为监视服务可能需要几毫秒才能获得通知并关闭句柄。如果在此期间该工具尝试删除父目录,那么它将失败。我们目前没有解决此问题的方法。

于 2012-09-07T17:09:19.263 回答