Java目錄事件

當文件系統中的對象被修改時,我們可以監聽watch服務以獲取警報。java.nio.file包中的以下類和接口提供watch服務。

  • Watchable接口
  • WatchService接口
  • WatchKey接口
  • WatchEvent接口
  • WatchEvent.Kind接口
  • StandardWatchEventKinds類

Watchable對象表示可以被監視的文件系統對象。Watchable對象可以向watch服務註冊。
Path對象是一個Watchable對象。

WatchService表示觀察服務。當一個對象使用WatchService註冊時,WatchService返回一個WatchKey作爲註冊的令牌。WatchEvent表示註冊到監視服務的對象上的事件。 它的kind()方法返回發生的事件的類型。
它的context()方法返回一個Path對象,它表示事件發生的條目。count()方法返回特定通知的事件發生次數。 如果它返回的值大於1,那麼它是一個重複的事件。

WatchEvent.Kind <T>表示發生的事件的類型。StandardWatchEventKinds類定義了用於表示事件種類的常量,如下所示。

  • ENTRY_CREATE
  • ENTRY_DELETE
  • ENTRY_MODIFY
  • OVERFLOW

OVERFLOW表示丟失或丟棄的事件。創建觀察服務用來觀察目錄,以進行進一步更改。

WatchService ws = FileSystems.getDefault().newWatchService();

要使用Watch服務註冊目錄,請使用register()方法,該方法將返回一個WatchKey對象作爲註冊令牌。

// Get  a  Path  object for C:\myName  directory  to watch
Path  dirToWatch  = Paths.get("C:\\myName");
WatchKey token   = dirToWatch.register(ws, ENTRY_CREATE,  ENTRY_MODIFY,  ENTRY_DELETE);

要取消註冊,請使用WatchKeycancel()方法。當註冊目錄時,其WatchKey處於就緒狀態。可以通過手錶服務註冊多個目錄。

要從監視服務隊列中檢索WatchKey,請使用WatchService對象的take()poll()方法檢索並刪除發出信號並排隊的WatchKey
take()方法等待,直到WatchKey可用。poll()方法可用於爲等待指定超時時間值。

以下代碼使用無限循環來檢索發出信號的WatchKey

while(true)  {
    WatchKey key  = ws.take();
}

處理事件

WatchKeypollEvents()方法檢索並刪除其所有掛起的事件。它返回一個WatchEvent的列表-ListList的每個元素代表WatchKey上的一個事件。

以下代碼顯示了處理事件的典型邏輯:

while(true)  {
    WatchKey key  = ws.take();
    // Process all  events of  the   WatchKey 
    for(WatchEvent<?> event  : key.pollEvents())  {
       // Process each  event here
    }
}

處理事件後重置WatchKey

如果要重置WatchKey對象,通過調用它的reset()方法來再次接收事件通知。

reset()方法將WatchKey置於就緒狀態。如果WatchKey仍然有效,reset()方法返回true,否則它返回false

如果WatchKey被取消或其監視服務關閉,它可能會失效。

// Reset   the   WatchKey
boolean isKeyValid = key.reset();
if (!isKeyValid)  {
    System.out.println("No  longer  watching "  + dirToWatch);
}

WatchService是可自動關閉的。可以在try-with-resources塊中創建一個WatchService對象,當程序退出塊時,它會自動關閉。

示例

以下代碼顯示瞭如何實現監視服務以監視目錄中的更改。

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.Path;
import java.nio.file.Paths;
import java.nio.file.WatchEvent;
import java.nio.file.WatchEvent.Kind;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;

public class Main {
  public static void main(String[] args) {
    try (WatchService ws = FileSystems.getDefault().newWatchService()) {
      Path dirToWatch = Paths.get("C:\\myName");
      dirToWatch.register(ws, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE);
      while (true) {
        WatchKey key = ws.take();
        for (WatchEvent<?> event : key.pollEvents()) {
          Kind<?> eventKind = event.kind();
          if (eventKind == OVERFLOW) {
            System.out.println("Event  overflow occurred");
            continue;
          }
          WatchEvent<Path> currEvent = (WatchEvent<Path>) event;
          Path dirEntry = currEvent.context();
          System.out.println(eventKind + "  occurred on  " + dirEntry);
        }
        boolean isKeyValid = key.reset();
        if (!isKeyValid) {
          System.out.println("No  longer  watching " + dirToWatch);
          break;
        }
      }
    } catch (IOException | InterruptedException e) {
      e.printStackTrace();
    }
  }
}