2014-05-04 10 views
23

Ich möchte ein Verzeichnis für Dateiänderungen sehen. Und ich habe WatchService in java.nio verwendet. Ich kann erfolgreich auf Dateiereignisse warten. Aber ich kann nicht auf Dateiänderungsereignisse warten. Ich überprüfte official java tutorial, aber immer noch kämpfen.Ein Verzeichnis nach Änderungen in Java beobachten

Hier ist der Quellcode.

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

import java.io.File; 
import java.io.IOException; 
import java.nio.file.FileSystem; 
import java.nio.file.Files; 
import java.nio.file.Path; 
import java.nio.file.WatchEvent; 
import java.nio.file.WatchEvent.Kind; 
import java.nio.file.WatchKey; 
import java.nio.file.WatchService; 

public class MainWatch { 

    public static void watchDirectoryPath(Path path) { 
     // Sanity check - Check if path is a folder 
     try { 
      Boolean isFolder = (Boolean) Files.getAttribute(path, 
        "basic:isDirectory", NOFOLLOW_LINKS); 
      if (!isFolder) { 
       throw new IllegalArgumentException("Path: " + path 
         + " is not a folder"); 
      } 
     } catch (IOException ioe) { 
      // Folder does not exists 
      ioe.printStackTrace(); 
     } 

     System.out.println("Watching path: " + path); 

     // We obtain the file system of the Path 
     FileSystem fs = path.getFileSystem(); 

     // We create the new WatchService using the new try() block 
     try (WatchService service = fs.newWatchService()) { 

      // We register the path to the service 
      // We watch for creation events 
      path.register(service, ENTRY_CREATE); 
      path.register(service, ENTRY_MODIFY); 
      path.register(service, ENTRY_DELETE); 

      // Start the infinite polling loop 
      WatchKey key = null; 
      while (true) { 
       key = service.take(); 

       // Dequeueing events 
       Kind<?> kind = null; 
       for (WatchEvent<?> watchEvent : key.pollEvents()) { 
        // Get the type of the event 
        kind = watchEvent.kind(); 
        if (OVERFLOW == kind) { 
         continue; // loop 
        } else if (ENTRY_CREATE == kind) { 
         // A new Path was created 
         Path newPath = ((WatchEvent<Path>) watchEvent) 
           .context(); 
         // Output 
         System.out.println("New path created: " + newPath); 
        } else if (ENTRY_MODIFY == kind) { 
         // modified 
         Path newPath = ((WatchEvent<Path>) watchEvent) 
           .context(); 
         // Output 
         System.out.println("New path modified: " + newPath); 
        } 
       } 

       if (!key.reset()) { 
        break; // loop 
       } 
      } 

     } catch (IOException ioe) { 
      ioe.printStackTrace(); 
     } catch (InterruptedException ie) { 
      ie.printStackTrace(); 
     } 

    } 

    public static void main(String[] args) throws IOException, 
      InterruptedException { 
     // Folder we are going to watch 
     // Path folder = 
     // Paths.get(System.getProperty("C:\\Users\\Isuru\\Downloads")); 
     File dir = new File("C:\\Users\\Isuru\\Downloads"); 
     watchDirectoryPath(dir.toPath()); 
    } 
    } 
+0

Welche OS und Java-Version? – MadProgrammer

+0

Windows 8 und Java 1.7 – Isuru

+2

Haben Sie das "Lager" [WatchDir.java] (http://docs.oracle.com/javase/tutorial/essential/io/examples/WatchDir.java) ausprobiert? Es funktioniert zumindest unter Linux. – user3159253

Antwort

20

Eigentlich haben Sie Ereignisse falsch abonniert. Nur der letzte Listener wurde mit dem ENTRY_DELETE-Ereignistyp registriert.

für alle Arten von Veranstaltungen registrieren Sie verwenden sollten:

path.register(service, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE); 
14

Achtung! Schamlose Selbstwerbung!

Ich habe einen Wrapper um Java 1.7 WatchService erstellt, die Registrierung eines Verzeichnisses und einer beliebigen Anzahl von Glob Muster ermöglicht. Diese Klasse kümmert sich um die Filterung und nur emittieren Ereignisse, die Sie interessieren.

DirectoryWatchService watchService = new SimpleDirectoryWatchService(); // May throw 
watchService.register(// May throw 
     new DirectoryWatchService.OnFileChangeListener() { 
      @Override 
      public void onFileCreate(String filePath) { 
       // File created 
      } 

      @Override 
      public void onFileModify(String filePath) { 
       // File modified 
      } 

      @Override 
      public void onFileDelete(String filePath) { 
       // File deleted 
      } 
     }, 
     <directory>, // Directory to watch 
     <file-glob-pattern-1>, // E.g. "*.log" 
     <file-glob-pattern-2>, // E.g. "input-?.txt" 
     ... // As many patterns as you like 
); 

watchService.start(); 

komplette Code ist in diesem Gist.

+0

Upvote für die komplette Lösung. Eine kleine Empfehlung, beachten Sie, dass das Beispiel nur auf Java 8 funktioniert. Versteht mich nicht falsch, ich liebe Lambdas, aber Java 7 ist heutzutage viel häufiger, also musste ich es zu Java 7 nachrüsten, als ich es benutzte. Ich werde bald die "fixed" Version für diejenigen veröffentlichen, die Java 8 noch nicht benutzen können. – nterry

+0

Hey, vielen Dank für die Mühe. Die Firma, für die ich arbeite, ist bereits auf Java 8 umgestiegen, seit der Java 7 Support-Zyklus beendet ist. Aus diesem Grund hatte ich keinen zwingenden Grund, Java 7 zu unterstützen. Ich werde den Gist-Titel entsprechend aktualisieren. – Hindol

+0

Ich habe gerade heruntergeladen die Gist Zip und versuchte es mit Java 1.7. Es kann nicht 'import java.util.stream' und einige' default' Methoden finden. @nterry Hast du die Java 7 Version irgendwo veröffentlicht? Tnks. – elysch

2

Ich habe einige Klassen dafür gemacht.

public interface FileAvailableListener { 
    public void fileAvailable(File file) throws IOException; 
} 

und

public class FileChange { 

private long lastModified; 
private long size; 
private long lastCheck; 

public FileChange(File file) { 
    this.lastModified=file.lastModified(); 
    this.size=file.length(); 
    this.lastCheck = System.currentTimeMillis(); 
} 

public long getLastModified() { 
    return lastModified; 
} 
public long getSize() { 
    return size; 
} 
public long getLastCheck() { 
    return lastCheck; 
} 

public boolean isStable(FileChange other,long stableTime) { 
    boolean b1 = (getLastModified()==other.getLastModified()); 
    boolean b2 = (getSize()==other.getSize()); 
    boolean b3 = ((other.getLastCheck()-getLastCheck())>stableTime); 
    return b1 && b2 && b3; 
} 
} 

und

public class DirectoryWatcher { 

private Timer timer; 
private List<DirectoryMonitorTask> tasks = new ArrayList<DirectoryMonitorTask>(); 

public DirectoryWatcher() throws URISyntaxException, IOException, InterruptedException { 
    super(); 
    timer = new Timer(true);   
} 
public void addDirectoryMonitoringTask(DirectoryMonitorTask task,long period) { 
    tasks.add(task); 
    timer.scheduleAtFixedRate(task, 5000, period);  
} 
public List<DirectoryMonitorTask> getTasks() { 
    return Collections.unmodifiableList(tasks); 
} 
public Timer getTimer() { 
    return timer; 
} 
} 

und

class DirectoryMonitorTask extends TimerTask { 

public final static String DIRECTORY_NAME_ARCHIVE="archive"; 
public final static String DIRECTORY_NAME_ERROR="error"; 
public final static String LOCK_FILE_EXTENSION=".lock"; 
public final static String ERROR_FILE_EXTENSION=".error"; 
public final static String FILE_DATE_FORMAT="yyyyMMddHHmmssSSS"; 

private String name; 
private FileAvailableListener listener; 
private Path directory; 
private File directoryArchive; 
private File directoryError; 
private long stableTime; 
private FileFilter filter; 
private WatchService watchService; 
private SimpleDateFormat dateFormatter = new SimpleDateFormat(FILE_DATE_FORMAT); 
private Hashtable<File,FileChange> fileMonitor = new Hashtable<File,FileChange>(); 

public DirectoryMonitorTask(String name,FileAvailableListener listener,Path directory,long stableTime,FileFilter filter) throws IOException { 
    super(); 
    this.name=name; 
    this.listener=listener; 
    this.directory=directory; 
    this.stableTime=stableTime; 
    if (stableTime<1) { 
     stableTime=1000; 
    } 
    this.filter=filter; 
    validateNotNull("Name",name); 
    validateNotNull("Listener",listener); 
    validateNotNull("Directory",directory); 
    validate(directory); 
    directoryArchive = new File(directory.toFile(),DIRECTORY_NAME_ARCHIVE); 
    directoryError = new File(directory.toFile(),DIRECTORY_NAME_ERROR); 
    directoryArchive.mkdir(); 
    directoryError.mkdir(); 
    // 
    log("Constructed for "+getDirectory().toFile().getAbsolutePath()); 

    initialize(); 
    // 
    watchService = FileSystems.getDefault().newWatchService(); 
    directory.register(watchService,StandardWatchEventKinds.ENTRY_CREATE,StandardWatchEventKinds.ENTRY_DELETE,StandardWatchEventKinds.ENTRY_MODIFY); 
    log("Started"); 
} 

private void initialize() { 
    File[] files = getDirectory().toFile().listFiles(); 
    for (File file : files) { 
     if (isLockFile(file)) { 
      file.delete(); 
     } else if (acceptFile(file)) { 
      fileMonitor.put(file,new FileChange(file)); 
      log("Init file added -"+file.getName()); 
     } 
    } 
} 
public SimpleDateFormat getDateFormatter() { 
    return dateFormatter; 
} 
public Path getDirectory() { 
    return directory; 
} 
public FileAvailableListener getListener() { 
    return listener; 
} 
public String getName() { 
    return name; 
} 
public WatchService getWatchService() { 
    return watchService; 
} 
public long getStableTime() { 
    return stableTime; 
} 
public File getDirectoryArchive() { 
    return directoryArchive; 
} 
public File getDirectoryError() { 
    return directoryError; 
} 
public FileFilter getFilter() { 
    return filter; 
} 
public Iterator<File> getMonitoredFiles() { 
    return fileMonitor.keySet().iterator(); 
} 

@Override 
public void run() { 
    WatchKey key; 
    try { 
     key = getWatchService().take(); 
     // Poll all the events queued for the key 
     for (WatchEvent<?> event : key.pollEvents()) {          
      @SuppressWarnings("unchecked") 
      Path filePath = ((WatchEvent<Path>) event).context(); 
      File file = filePath.toFile(); 
      if ((!isLockFile(file)) && (acceptFile(file))) { 
       switch (event.kind().name()) { 
        case "ENTRY_CREATE": 
         //       
         fileMonitor.put(file,new FileChange(file)); 
         log("File created ["+file.getName()+"]"); 
         break; 
         // 
        case "ENTRY_MODIFY": 
         //       
         fileMonitor.put(file,new FileChange(file)); 
         log("File modified ["+file.getName()+"]"); 
         break; 
         // 
        case "ENTRY_DELETE": 
         // 
         log("File deleted ["+file.getName()+"]"); 
         createLockFile(file).delete(); 
         fileMonitor.remove(file);       
         break; 
         // 
       } 
      } 
     } 
     // reset is invoked to put the key back to ready state 
     key.reset(); 
    } catch (InterruptedException e) {    
     e.printStackTrace(); 
    } 

    Iterator<File> it = fileMonitor.keySet().iterator(); 

    while (it.hasNext()) { 
     File file = it.next(); 
     FileChange fileChange = fileMonitor.get(file); 
     FileChange fileChangeCurrent = new FileChange(file); 

     if (fileChange.isStable(fileChangeCurrent, getStableTime())) { 
      log("File is stable ["+file.getName()+"]"); 
      String filename = getDateFormatter().format(new Date())+"_"+file.getName(); 
      File lockFile = createLockFile(file); 
      if (!lockFile.exists()) { 
       log("File do not has lock file ["+file.getName()+"]"); 
       try { 
        Files.createFile(lockFile.toPath()); 
        log("Processing file ["+file.getName()+"]"); 
        getListener().fileAvailable(file);      
        file.renameTo(new File(getDirectoryArchive(),filename)); 
        log("Moved to archive file ["+file.getName()+"]"); 
       } catch (IOException e) {      
        file.renameTo(new File(getDirectoryError(),filename)); 
        createErrorFile(file,e); 
        log("Moved to error file ["+file.getName()+"]"); 
       } finally { 
        lockFile.delete(); 

       } 
      } else {      
       log("File do has lock file ["+file.getName()+"]"); 
       fileMonitor.remove(file); 
      }    
     } else {     
      log("File is unstable ["+file.getName()+"]"); 
      fileMonitor.put(file,fileChangeCurrent); 
     } 
    }  
} 

public boolean acceptFile(File file) { 
    if (getFilter()!=null) { 
     return getFilter().accept(file); 
    } else { 
     return true; 
    }  
} 

public boolean isLockFile(File file) { 
    int pos = file.getName().lastIndexOf('.'); 
    String extension=""; 
    if (pos!=-1) { 
     extension = file.getName().substring(pos).trim().toLowerCase(); 
    } 
    return(extension.equalsIgnoreCase(LOCK_FILE_EXTENSION)); 
} 

private File createLockFile(File file) { 
    return new File(file.getParentFile(),file.getName()+LOCK_FILE_EXTENSION); 
} 

private void createErrorFile(File file,IOException exception) { 
    File errorFile = new File(file.getParentFile(),file.getName()+ERROR_FILE_EXTENSION); 

    StringWriter sw = null; 
    PrintWriter pw = null; 
    FileWriter fileWriter = null; 
    try { 
     //   
     fileWriter = new FileWriter(errorFile); 
     if (exception!=null) { 
      sw = new StringWriter(); 
      pw = new PrintWriter(sw); 
      exception.printStackTrace(pw);  
      fileWriter.write(sw.toString()); 
     } else { 
      fileWriter.write("Exception is null."); 
     } 
     //  
     fileWriter.flush(); 
     // 
    } catch (IOException e) { 
    } finally { 
     if (sw!=null) { 
      try { 
       sw.close(); 
      } catch (IOException e1) {    
      } 
     } 
     if (pw!=null) { 
      pw.close(); 
     } 
     if (fileWriter!=null) { 
      try { 
       fileWriter.close(); 
      } catch (IOException e) {     
      } 
     } 
    } 
} 

private void validateNotNull(String name,Object obj) { 
    if (obj==null) { 
     throw new NullPointerException(name+" is null."); 
    }   
}  
private void validate(Path directory) throws IOException {   
    File file = directory.toFile(); 
    if (!file.exists()) { 
     throw new IOException("Directory ["+file.getAbsolutePath()+"] do not exists."); 
    } else if (!file.isDirectory()) { 
     throw new IOException("Directory ["+file.getAbsolutePath()+"] is not a directory."); 
    } else if (!file.canRead()) {    
     throw new IOException("Can not read from directory ["+file.getAbsolutePath()+"]."); 
    } else if (!file.canWrite()) { 
     throw new IOException("Can not write to directory ["+file.getAbsolutePath()+"] ."); 
    }  
} 

private void log(String msg) { 
    //TODO 
    System.out.println("Task ["+getName()+"] "+msg); 
} 
} 
0
package p1; 

import java.io.File; 
import java.io.IOException; 
import java.nio.file.Files; 
import java.nio.file.Path; 
import java.nio.file.Paths; 
import static java.nio.file.LinkOption.NOFOLLOW_LINKS; 
import java.nio.file.StandardWatchEventKinds; 
import java.nio.file.WatchEvent; 
import java.nio.file.WatchKey; 
import java.nio.file.WatchService; 
import java.util.List; 

public class WatchForFile { 

    public void WatchMyFolder(String path) 
    { 
     File dir = new File(path); 
     Path myDir= dir.toPath(); 
      try 
      { 
       Boolean isFolder = (Boolean) Files.getAttribute(myDir,"basic:isDirectory", NOFOLLOW_LINKS); 
       if (!isFolder) 
       { 
        throw new IllegalArgumentException("Path: " + myDir + " is not a folder"); 
       } 
      } 
      catch (IOException ioe) 
      { 
       ioe.printStackTrace(); 
      } 

      System.out.println("Watching path: " + myDir); 

     try { 
      WatchService watcher = myDir.getFileSystem().newWatchService(); 
      myDir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE,StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY); 

      WatchKey watckKey = watcher.take(); 

      List<WatchEvent<?>> events = watckKey.pollEvents(); 

      for (WatchEvent event : events) { 
       if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE) { 
        System.out.println("Created: " + event.kind().toString()); 

       } 
       if (event.kind() == StandardWatchEventKinds.ENTRY_DELETE) { 
        System.out.println("Delete: " + event.context().toString()); 
       } 
       if (event.kind() == StandardWatchEventKinds.ENTRY_MODIFY) { 
        System.out.println("Modify: " + event.context().toString()); 
       } 
      } 

     } 
     catch (Exception e) 
     { 
      System.out.println("Error: " + e.toString()); 
     } 
    } 
}