2017-05-21 55 views
0

我有一個觀察者,當更改被聽到時更新我的​​數據結構。但是,如果更改不是即時的(即,如果正在從另一個文件系統複製大文件,或者修改了大部分文件),數據結構會嘗試更新得太早並引發錯誤。Java觀察服務 - 等待修改完成

如何修改我的代碼,以便updateData()之後最後ENTRY_MODIFY稱爲被調用,而不是每一個ENTRY_MODIFY後。

private static boolean processWatcherEvents() { 
    WatchKey key; 
    try { 
     key = watcher.poll(10, TimeUnit.MILLISECONDS); 
    } catch (InterruptedException e) { 
     return false; 
    } 

    Path directory = keys.get(key); 
    if (directory == null) { 
     return false; 
    } 

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

     WatchEvent <Path> watchEvent = (WatchEvent<Path>)event; 
     Path child = directory.resolve(watchEvent.context()); 

     if (eventKind == StandardWatchEventKinds.ENTRY_MODIFY) { 
      //TODO: Wait until modifications are "finished" before taking these actions. 
      if (Files.isDirectory(child)) { 
       updateData(child); 
      } 
     } 

     boolean valid = key.reset(); 
     if (!valid) { 
      keys.remove(key); 
     } 
    } 

    return true; 
} 
+0

你試過分配的孩子一個varialbe,循環結束後,執行updateDate?或者我在這裏錯過了這個想法? – Beri

+0

我認爲我給出的答案[這裏](http://stackoverflow.com/a/34718685/243373)可能是你需要的,至少是輪廓。 –

+0

是我給任何用途的鏈接的答案? –

回答

0

您的問題可以通過使用時間戳來解決。 創建地圖以將時間戳存儲到地圖。

Map<Path, Long> fileTimeStamps; 

用於處理事件檢查上次修改時間戳。

long oldFileModifiedTimeStamp = fileTimeStamps.get(filePath); 
long newFileModifiedTimeStamp = filePath.toFile().lastModified(); 
       if (newFileModifiedTimeStamp > oldFileModifiedTimeStamp) 
       { 
        fileTimeStamps.remove(filePath); 
        onEventOccurred(); 
        fileTimeStamps.put(filePath, filePath.toFile().lastModified()); 
       } 
0

我最後寫的是不斷的事情要更新和延遲實際上不更新,直到80毫秒已通過列表的線程。每當事件發生時,它都會重置計數器。我認爲這是一個很好的解決方案,但可能會更好?

@SuppressWarnings({ "rawtypes", "unchecked" }) 
private static boolean processWatcherEvents() { 
    WatchKey key; 
    try { 
     key = watcher.poll(10, TimeUnit.MILLISECONDS); 
    } catch (InterruptedException e) { 
     return false; 
    } 

    Path directory = keys.get(key); 
    if (directory == null) { 
     return false; 
    } 

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

     WatchEvent <Path> watchEvent = (WatchEvent<Path>)event; 
     Path child = directory.resolve(watchEvent.context()); 

     if (eventKind == StandardWatchEventKinds.ENTRY_CREATE) { 
      if (Files.isDirectory(child)) { 
       loadMe.add(child); 
      } else { 
       loadMe.add(child.getParent()); 
      } 

     } else if (eventKind == StandardWatchEventKinds.ENTRY_DELETE) { 
      //Handled by removeMissingFiles(), can ignore. 

     } else if (eventKind == StandardWatchEventKinds.ENTRY_MODIFY) { 
      System.out.println("Modified: " + child.toString()); //TODO: DD 
      if (Files.isDirectory(child)) { 
       modifiedFileDelayedUpdater.addUpdateItem(child); 
      } else { 
       modifiedFileDelayedUpdater.addUpdateItem(child); 
      } 

     } else if (eventKind == StandardWatchEventKinds.OVERFLOW) { 
      for (Path path : musicSourcePaths) { 
       updateMe.add(path); 
      } 
     } 

     boolean valid = key.reset(); 
     if (!valid) { 
      keys.remove(key); 
     } 
    } 

    return true; 
} 

...

class UpdaterThread extends Thread { 
    public static final int DELAY_LENGTH_MS = 80; 
    public int counter = DELAY_LENGTH_MS; 

    Vector <Path> updateItems = new Vector <Path>(); 

    public void run() { 
     while (true) { 
      long sleepTime = 0; 
      try { 
       long startSleepTime = System.currentTimeMillis(); 
       Thread.sleep (20); 
       sleepTime = System.currentTimeMillis() - startSleepTime; 
      } catch (InterruptedException e) {} //TODO: Is this OK to do? Feels like a bad idea. 

      if (counter > 0) { 
       counter -= sleepTime; 

      } else if (updateItems.size() > 0) { 
       Vector <Path> copyUpdateItems = new Vector<Path> (updateItems); 
       for (Path path : copyUpdateItems) { 
        Library.requestUpdate (path); 
        updateItems.remove(path); 

       } 
      } 
     } 
    } 

    public void addUpdateItem (Path path) { 
     counter = DELAY_LENGTH_MS; 
     if (!updateItems.contains(path)) { 
      updateItems.add (path); 
     } 
    } 
};