2016-05-13 84 views
0

我在我的應用程序中使用Java觀看服務來獲取任何文件更改的通知。觀看服務獲取文件句柄

但問題是watch service存放父目錄的文件句柄。 例如如果我的等級是

F 
-F1 
-F2 

當我註冊F,F1和F2的觀看服務。然後,如果我嘗試重命名或刪除父文件夾F,則會出現文件消息由另一個程序即Watch服務打開。

我發現這裏提到http://bugs.java.com/bugdatabase/view_bug.do;jsessionid=76a42b61021a94ffffffffa049f7587fd4149?bug_id=6972833

而且已經試過File_Tree修飾符來規避這個問題這個問題,但它並沒有幫助。可能我沒有正確使用File_Tree修飾符。

下面是我正在測試的示例代碼。請檢查我的代碼中FILE_TREE修飾符的用法是否正確。

/** 
* Example to watch a directory (or tree) for changes to files. 
* This code is direct copy from https://docs.oracle.com/javase/tutorial/essential/io/examples/WatchDir.java 
*/ 

public class FileWatcher { 

    private final WatchService watcher; 
    private final Map<WatchKey,Path> keys; 
    private final boolean recursive; 
    private boolean trace = false; 

    @SuppressWarnings("unchecked") 
    static <T> WatchEvent<T> cast(WatchEvent<?> event) { 
     return (WatchEvent<T>)event; 
    } 

    /** 
    * Register the given directory with the WatchService 
    */ 
    private void register(Path dir) throws IOException { 
     WatchKey key = dir.register(watcher, new WatchEvent.Kind[] { ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY, OVERFLOW },com.sun.nio.file.ExtendedWatchEventModifier.FILE_TREE); 
     if (trace) { 
      Path prev = keys.get(key); 
      if (prev == null) { 
       System.out.format("register: %s\n", dir); 
      } else { 
       if (!dir.equals(prev)) { 
        System.out.format("update: %s -> %s\n", prev, dir); 
       } 
      } 
     } 
     keys.put(key, dir); 
    } 

    /** 
    * Register the given directory, and all its sub-directories, with the 
    * WatchService. 
    */ 
    private void registerAll(final Path start) throws IOException { 
     // register directory and sub-directories 
     Files.walkFileTree(start, new SimpleFileVisitor<Path>() { 
      @Override 
      public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) 
        throws IOException 
        { 
       register(dir); 
       return FileVisitResult.CONTINUE; 
        } 
     }); 
    } 

    /** 
    * Creates a WatchService and registers the given directory 
    */ 
    FileWatcher(Path dir, boolean recursive) throws IOException { 
     this.watcher = FileSystems.getDefault().newWatchService(); 
     this.keys = new HashMap<WatchKey,Path>(); 
     this.recursive = recursive; 

     if (recursive) { 
      System.out.format("Scanning %s ...\n", dir); 
      registerAll(dir); 
      System.out.println("Done."); 
     } else { 
      register(dir); 
     } 

     // enable trace after initial registration 
     this.trace = true; 
    } 

    /** 
    * Process all events for keys queued to the watcher 
    */ 
    void processEvents() { 
     for (;;) { 

      // wait for key to be signalled 
      WatchKey key; 
      try { 
       key = watcher.take(); 
      } catch (InterruptedException x) { 
       return; 
      } 

      Path dir = keys.get(key); 
      if (dir == null) { 
       System.err.println("WatchKey not recognized!!"); 
       continue; 
      } 

      for (WatchEvent<?> event: key.pollEvents()) { 
       WatchEvent.Kind kind = event.kind(); 

       // TBD - provide example of how OVERFLOW event is handled 
       if (kind == OVERFLOW) { 
        continue; 
       } 

       // Context for directory entry event is the file name of entry 
       WatchEvent<Path> ev = cast(event); 
       Path name = ev.context(); 
       Path child = dir.resolve(name); 

       // print out event 
       System.out.format("%s: %s\n", event.kind().name(), child); 

       // if directory is created, and watching recursively, then 
       // register it and its sub-directories 
       if (recursive && kind == ENTRY_CREATE) { 
        try { 
         if (Files.isDirectory(child, NOFOLLOW_LINKS)) { 
          registerAll(child); 
         } 
        } catch (IOException x) { 
         // ignore to keep sample readbale 
        } 
       } 
      } 

      // reset key and remove from set if directory no longer accessible 
      boolean valid = key.reset(); 
      if (!valid) { 
       keys.remove(key); 

       // all directories are inaccessible 
       if (keys.isEmpty()) { 
        break; 
       } 
      } 
     } 
    } 

    static void usage() { 
     System.err.println("usage: java WatchDir [-r] dir"); 
     System.exit(-1); 
    } 

    public static void main(String[] args) throws IOException { 
     // parse arguments 
     if (args.length == 0 || args.length > 2) { 
      usage(); 
     } 
     boolean recursive = false; 
     int dirArg = 0; 
     if (args[0].equals("-r")) { 
      if (args.length < 2) { 
       usage(); 
      } 
      recursive = false; 
      dirArg++; 
     } 

     // register directory and process its events 
     Path dir = Paths.get(args[dirArg]); 
     new FileWatcher(dir, recursive).processEvents(); 
    } 
} 

回答

0

在文檔中挖了一點點,找到了自己的修復方法。

使用File_Tree修飾符,將單個鍵分配給所有文件夾/目錄。所以我們需要使用一個鍵。 因此,我正在嘗試使用相同的根路徑重新註冊,然後在每個新創建的目錄下的項目上重新使用該密鑰。

主要拿走的題是不是不再需要在目錄中的每個文件夾visting的

  1. 遞歸的方式。
  2. 無論何時在根路徑下創建新文件夾時都需要在相同路徑上重新註冊,因爲每次只需要密鑰
  3. 因爲每次我註冊整個路徑,所以我不確定性能部分。我可能會做一些性能分析。

下面是我的代碼的修改版本。讓我知道如果代碼不清晰

package com.sap.mcm; 


import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; 
import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE; 
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; 
import static java.nio.file.StandardWatchEventKinds.OVERFLOW; 

import java.io.IOException; 
import java.nio.file.FileSystems; 
import java.nio.file.FileVisitResult; 
import java.nio.file.Files; 
import java.nio.file.Path; 
import java.nio.file.Paths; 
import java.nio.file.SimpleFileVisitor; 
import java.nio.file.WatchEvent; 
import java.nio.file.WatchKey; 
import java.nio.file.WatchService; 
import java.nio.file.attribute.BasicFileAttributes; 
import java.util.HashMap; 
import java.util.Map; 

import com.sun.nio.file.ExtendedWatchEventModifier; 
/** 
* Example to watch a directory (or tree) for changes to files. 
* This code is direct copy from https://docs.oracle.com/javase/tutorial/essential/io/examples/WatchDir.java 
*/ 

public class FileWatcher { 

    private final WatchService watcher; 
    private final Map<WatchKey,Path> keys; 
    private final boolean recursive; 
    private boolean trace = true; 
    private Path parentDir; 
    private WatchKey key; 

    @SuppressWarnings("unchecked") 
    static <T> WatchEvent<T> cast(WatchEvent<?> event) { 
     return (WatchEvent<T>)event; 
    } 

    /** 
    * Register the given directory with the WatchService 
    */ 
    private void register(Path dir) throws IOException { 
     try { 
      parentDir = dir; 
      key = parentDir.register(watcher, new WatchEvent.Kind[] { ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY, OVERFLOW }, ExtendedWatchEventModifier.FILE_TREE); 
     } catch (UnsupportedOperationException usoe) { 
      usoe.printStackTrace(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    public void reregister() throws IOException { 
     // WatchKey key = keys.get(path); 
     key.cancel(); 
     register(parentDir); 
    } 
    /** 
    * Register the given directory, and all its sub-directories, with the 
    * WatchService. 
    */ 
    private void registerAll(final Path start) throws IOException { 
     // register directory and sub-directories 
     Files.walkFileTree(start, new SimpleFileVisitor<Path>() { 
      @Override 
      public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) 
        throws IOException 
        { 
       register(dir); 
       return FileVisitResult.CONTINUE; 
        } 
     }); 
    } 

    /** 
    * Creates a WatchService and registers the given directory 
    */ 
    FileWatcher(Path dir, boolean recursive) throws IOException { 
     this.watcher = FileSystems.getDefault().newWatchService(); 
     this.keys = new HashMap<WatchKey,Path>(); 
     this.recursive = recursive; 

     if (recursive) { 
      System.out.format("Scanning %s ...\n", dir); 
      registerAll(dir); 
      System.out.println("Done."); 
     } else { 
      register(dir); 
     } 

     // enable trace after initial registration 
     this.trace = true; 
    } 

    /** 
    * Process all events for keys queued to the watcher 
    */ 
    void processEvents() { 
     for (;;) { 

      // wait for key to be signalled 
      WatchKey key; 
      try { 
       key = watcher.take(); 
      } catch (InterruptedException x) { 
       return; 
      } 

      // Path dir = keys.get(key); 
      // if (dir == null) { 
      // System.err.println("WatchKey not recognized!!"); 
      // continue; 
      // } 
      if (this.key != key) { 
       return; 
      } 
      for (WatchEvent<?> event: key.pollEvents()) { 
       WatchEvent.Kind kind = event.kind(); 

       // TBD - provide example of how OVERFLOW event is handled 
       if (kind == OVERFLOW) { 
        continue; 
       } 

       // Context for directory entry event is the file name of entry 
       WatchEvent<Path> ev = cast(event); 
       ev.context(); 

       // print out event 
       System.out.format("%s: %s \n", event.kind().name(), event.context()); 

       // if directory is created, and watching recursively, then 
       // register it and its sub-directories 
       if (kind == ENTRY_CREATE) { 
        try { 
         // if (Files.isDirectory(child, NOFOLLOW_LINKS)) { 
         reregister(); 
         // } 
        } catch (IOException x) { 
         // ignore to keep sample readbale 
        } 
       } 
      } 

      // reset key and remove from set if directory no longer accessible 
      boolean valid = this.key.reset(); 
      if (!valid) { 
       keys.remove(key); 

       // all directories are inaccessible 
       if (keys.isEmpty()) { 
        break; 
       } 
      } 
     } 
    } 

    static void usage() { 
     System.err.println("usage: java WatchDir [-r] dir"); 
     System.exit(-1); 
    } 

    public static void main(String[] args) throws IOException { 
     // parse arguments 
     if (args.length == 0 || args.length > 2) { 
      usage(); 
     } 
     boolean recursive = false; 
     int dirArg = 0; 
     if (args[0].equals("-r")) { 
      if (args.length < 2) { 
       usage(); 
      } 
      recursive = false; 
      dirArg++; 
     } 

     // register directory and process its events 
     Path dir = Paths.get(args[dirArg]); 
     new FileWatcher(dir, recursive).processEvents(); 
    } 
}