2013-04-21 16 views
23
import java.io.*; 
import java.nio.file.*; 

public class Tmp { 

    public static void main(String [] args) throws IOException { 
     int count = 0; 
     Path path = Paths.get("C:\\tmp\\"); 
     WatchService ws = null; 
     try { 
      ws = FileSystems.getDefault().newWatchService(); 
      path.register(ws, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, 
        StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.OVERFLOW); 
     } catch (IOException ioe) { 
      ioe.printStackTrace(); 
     } 

     while(true) { 
      WatchKey key = null; 
      try { 
       key = ws.take(); 
      } catch(InterruptedException ie) { 
       ie.printStackTrace(); 
      } 

      for(WatchEvent<?> event: key.pollEvents()) { 
       switch(event.kind().name()) { 
        case "OVERFLOW": 
         System.out.println(++count + ": OVERFLOW"); 
         break; 
        case "ENTRY_MODIFY": 
         System.out.println(++count + ": File " + event.context() + " is changed!"); 
         break; 
        case "ENTRY_CREATE": 
         System.out.println(++count + ": File " + event.context() + " is created!"); 
         break; 
        case "ENTRY_DELETE": 
         System.out.println(++count + ": File " + event.context() + " is deleted!"); 
         break; 
        default: 
         System.out.println(++count + ": UNKNOWN EVENT!"); 
       } 
      } 

      key.reset(); 
     }  
    } 
} 

Quando ho eseguito questo e poi aperto il Notepad ++ e quindi creato un nuovo file vuoto e salvato come a.txt nella directory C:\tmp\ ho ottenuto l'output:Perché WatchService genera così tante operazioni?

1: File a.txt is created! 
2: File a.txt is deleted! 
3: File a.txt is created! 

Perché? Sembra che il file sia stato creato e poi cancellato e quindi creato di nuovo. Perché?

Quando ho messo un po 'di testo nel file e salvato l'output era:

4: File a.txt is changed! 
5: File a.txt is changed! 

Perché cambia due volte?

+5

Penso che il comportamento che stai vedendo con WatchService sia dovuto al modo in cui Notepad ++ e ad alcuni aspetti del funzionamento del sistema operativo Windows quando si eseguono operazioni IO. Ho scoperto che qualcosa come il blocco note "standard" di Windows di solito produce il comportamento più atteso. Ho il sospetto che se si utilizza Process Explorer (http://technet.microsoft.com/en-gb/sysinternals/bb896653.aspx) per monitorare l'attività di I/O a livello di sistema operativo, vedrai gli stessi risultati. –

+2

Ciò potrebbe essere dovuto al fatto che le scritture di contenuto e metadati vengono eseguite separatamente. – afk5min

risposta

0

Gli eventi di creazione e cancellazione di file funzionano correttamente nel mio sistema (Finestra 7 + 1.7.0_21).

Il messaggio di evento di modifica viene visualizzato il numero di di tempo (n) per ogni Ctrl +s operazione su quel file.

 // Removed the "//" after director name as D://tmp" 
     //Added just to see the message with a 1 ms gap. 
     Thread.sleep(1000); // after key.reset(); 

Esempio: Se apriamo il file e continuare a premere i Crtl + s (salva con le eventuali modifiche/con i cambiamenti). Il seguente messaggio mostrerà (ripetutamente) per ogni operazione di salvataggio.

Il motivo è in Windows WatchService sta confrontando le modifiche del file con timestamp anziché checksum.

Più descrizione qui Platform dependencies

+0

Questo non è un intervallo di 1ms, questo è un intervallo di 1 secondo. Ovviamente non vedrete l'effetto se aspettate molto tempo in termini informatici prima di riprovare. Per quanto segue: "Il motivo è in Windows WatchService sta confrontando le modifiche del file con timestamp anziché checksum". eh ... cosa? –

+0

@RobinGreen, per favore dimmi qual è la tua eccezione e la tua risposta. – VKPRO

0

dato questo funziona per me

// get the first event before looping 
    WatchKey key = this.watcher.take(); 

    // reset key (executed twice but not invoke the polled events) 
    while (key != null && key.reset()) { 
     // polled events 
     for (final WatchEvent<?> event : key.pollEvents()) { 
     System.out.printf("\nGlobal received: %s, event for file: %s\n", event.kind(), 
      event.context()); 

     switch (event.kind().name()) { 
     case "ENTRY_CREATE": 
      LOGGER.debug("event ENTRY_CREATE"); 
      break; 
     case "ENTRY_DELETE": 
      LOGGER.debug("event ENTRY_DELETE"); 
      break; 
     case "ENTRY_MODIFY": 
      LOGGER.debug("event ENTRY_MODIFY"); 
      break; 
     default: 
      LOGGER.debug("event other [OVERFLOW]"); 
      break; 
     } 
     } 

     key = this.watcher.take(); 
    } 
1

evento Modifica del Watch Service genera due eventi. Quando modifichiamo un file già esistente, il file system prima lo crea con 0 byte e spara un evento di modifica e quindi scrive i dati su di esso. Quindi spara di nuovo l'evento di modifica. Ecco perché mostrava due eventi di modifica. Così che cosa ho fatto per risolvere questo problema, mi basta usare contatore per controllare il mio compito dovrebbe essere attivato una sola volta nemmeno contare

 Path path = null; 
     int count = 0; 

     try { 
      path = Paths.get(new Utility().getConfDirPath()); 
      System.out.println("Path: " + path); 
     } catch (UnsupportedEncodingException e1) { 
      e1.printStackTrace(); 
     } 

     WatchService watchService = null; 
     try { 
      watchService = FileSystems.getDefault().newWatchService(); 
      path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY,StandardWatchEventKinds.ENTRY_DELETE); 
     } catch (IOException ioe) { 
      ioe.printStackTrace(); 
     } 


     while(true) { 
      WatchKey key = null; 
      try { 
       key = watchService.take(); 
      } catch(InterruptedException ie) { 
       ie.printStackTrace(); 
      } 

      for(WatchEvent<?> event: key.pollEvents()) { 
       switch(event.kind().name()) { 
        case "ENTRY_MODIFY": 
         System.out.println(++count + ": File " + event.context() + " is changed!"); 

         if (count%2==0) { 
          doOnChange(); // do whatever you want 
         } 
         break; 
        case "ENTRY_DELETE": 
         System.out.println(++count + ": File " + event.context() + " is deleted!"); 
         break; 
        default: 
         System.out.println(++count + ": UNKNOWN EVENT!"); 
       } 
      } 

      // reset the key 
      boolean valid = key.reset(); 
      if (!valid) { 
       System.out.println("Key has been unregistered"); 
      } 

     }  
0

ho creato un piccolo FileWatcher Utility Biblioteca: https://github.com/finsterwalder/fileutils

Permette di impostare un periodo di grazia. Più eventi all'interno del periodo di grazia vengono accumulati e attivati ​​solo una volta.

Non si dovrebbe usare Notepad ++ per i propri esperimenti, poiché non si sa cosa stia facendo Notepad ++. Potrebbe essere che Notepad ++ stia effettivamente scrivendo su un file più volte. O potrebbe scrivere un file con un nome diverso e rinominarlo, una volta fatto o quant'altro. Scrivi il tuo codice personale per manipolare i file e guardarli.