6

WatchServiceによって監視されているディレクトリが削除された場合、その親ディレクトリは File のlistFilesメソッドに削除をすぐに反映せず、削除できません。サービス全体が明示的に停止されるまで、親の結果は次のようになります。

  1. 空でないディレクトリを削除するための推奨される再帰的な解決策は失敗します。
  2. 正常終了時にdeleteOnExitが行われていない
  3. deleteの呼び出しは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);
    }
  }  
}

testDirファイルシステムで削除されていないことに対応する、Windowsで次の出力が得られます。

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 に答える