2011-12-12 73 views
23

我實現了一個文件觀察器,但我注意到java nio文件觀察器不會爲在映射驅動器上覆制的文件生成事件。例如,我在Unix上運行文件觀察器來觀察映射到窗口(H:\)上的本地目錄(/sharedfolder),然後我在該目錄中放置了一個文件(H:\),但文件觀察器沒有生成任何事件。現在,如果我在Windows上運行文件觀察器來觀察映射的驅動器(H:\),它指向unix路徑(/sharedfolder),並且從unix中將文件放入此文件夾,則文件觀察器將識別該更改並生成一個事件。它看起來像一個錯誤,或者可能是我錯過了一些事情,有什麼想法?Java WatchService在觀看映射驅動器時不生成事件

回答

4

JDK中的文件監視功能與平臺相關,因爲它使用本機庫,因此它可能在不同的平臺上表現不同。我很驚訝它適用於網絡驅動器--Windows必須輪詢網絡映射的驅動器以進行更改,而Linux不會(正常情況下我應該這麼說)。

通常這種在OS內核中實現的監視,顯然知道哪些文件在本地被修改/創建/等,但是OS沒有簡單的方法知道網絡驅動器上發生了什麼,因爲它沒有排他控制超過它。

+0

是的,但我正在看的目錄是在我運行我的監視器的同一臺機器上。因此,無論是通過網絡還是本地機器進行傳輸,操作系統都應該意識到這一點,否則如何完成傳輸。這是有道理的,Windows正在輪詢映射的驅動器,但我不明白Unix如何不知道通過本地文件夾上的網絡所做的更改。 – Ramcis

+0

@Ramcis:在Linux上,通過NFS安裝網絡共享,NFS設計爲無狀態協議。因此,服務器根本不知道有多少客戶端正在訪問哪個文件。該設計有一些優點(如較少的開銷)和一些缺點... – Robert

1

我在觀看遠程Windows目錄上的日誌文件內容的Python腳本時遇到了類似的問題。

這是我的答案。

當映射來自Unix的遠程驅動器,在使用/etc/fstab//xxx.xxx.xxx.xxx/shareddrive /media/shareddrive cifs username=xxxx,password=xxxx,**directio** 0 0

您可以使用證書文件,以避免在明文密碼。

該命令可能會根據unix版本而改變,這是在debian下測試的。 它應該按預期工作。 你能告訴我它是否有效嗎? 我計劃在Java中實現相同的東西,所以我的答案也可能對我有用。

+0

這不再工作順便說一句。我認爲它的工作方式有點片面(反正在ubuntu上),但在最近的更新之後,它完全停止了工作。我添加了一個答案來描述我可怕的解決方法。 – rubyruy

20

我有同樣的問題試圖通過CIFS觀看掛載的Windows共享。 看來不可能得到filesystem events for CIFS mounts

Java 7 NIO FileWatcher的Linux實現使用inotify。 Inotify是一個用於注意文件系統更改的Linux內核子系統,適用於本地目錄,但顯然不適用於CIFS mounts

在Oracle上,修復this bug似乎並不是高優先級。 (這是他們的責任?更多的操作系統問題...)

JNotify也使用inotify在Linux系統上,所以這也是沒有選擇。

所以映射驅動器監測不幸似乎僅限於輪詢:

  • Apache VFS DefaultFileMonitor輪詢目錄(安裝股)基於標準的Java API
  • 文件輪詢。
  • 自定義文件輪詢與jCIFS(這樣的比例並不需要安裝在主機上)

我可能會嘗試在Apache VFS顯示器,因爲它檢測到文件的創建,更新和刪除出盒子。它需要安裝共享,但是這給OS賦予了CIFS連接的責任,而不是我的應用程序。

1

我也碰到過這個,並得出了與其他人一樣的結論(CIFS + inotify = no go)。然而,由於我的工作流恰巧依賴於依賴inotify的遠程掛載和自動編譯工具,我最終構建了一個(相當絕望的& hacky)解決方案,它基本上只是使用輪詢來監視變化,然後觸及同樣的文件再次在安裝的一面,其中似乎引發inotify事件。這不是我最自豪的時刻。

話雖如此,它的工作,所以,可享受:http://github.com/rubyruy/watchntouch

1

我有同樣的問題。我已經通過在de main類中創建一個新線程並定期觸摸這些文件來解決這個問題,從而引發了一個新的更改事件。

該示例每10秒輪詢一次目錄會觸摸一下。

package com.ardevco.files; 

import java.io.IOException; 
import java.nio.file.DirectoryStream; 
import java.nio.file.Files; 
import java.nio.file.Path; 
import java.nio.file.Paths; 
import java.nio.file.attribute.FileTime; 
import java.util.ArrayList; 
import java.util.List; 

public class Touch implements Runnable { 

    private Path touchPath; 

    public Touch(Path touchPath) { 
     this.touchPath = touchPath; 
     this.checkPath = checkPath; 

    } 

    public static void touch(Path file) throws IOException { 
     long timestamp = System.currentTimeMillis(); 
     touch(file, timestamp); 
    } 

    public static void touch(Path file, long timestamp) throws IOException { 
     if (Files.exists(file)) { 
      FileTime ft = FileTime.fromMillis(timestamp); 
      Files.setLastModifiedTime(file, ft); 
     } 
    } 

    List<Path> listFiles(Path path) throws IOException { 
     final List<Path> files = new ArrayList<>(); 
     try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) { 
      for (Path entry : stream) { 
       if (Files.isDirectory(entry)) { 
        files.addAll(listFiles(entry)); 
       } 
       files.add(entry); 
      } 
     } 
     return files; 
    } 

    @Override 
    public void run() { 
     while (true) { 
      try { 
       for (Path path : listFiles(touchPath)) { 
        touch(path); 
       } 
      } catch (IOException e) { 
       System.out.println("Exception: " + e); 
      } 

      try { 
       Thread.sleep(10000L); 
      } catch (InterruptedException e) { 
       System.out.println("Exception: " + e); 
      } 
     } 

    } 

}