2014-05-04 18 views
23

Chcę obejrzeć katalog zmian plików. I użyłem WatchService w java.nio. Mogę pomyślnie odsłuchać zdarzenie utworzone przez plik. Ale nie mogę słuchać zdarzenia modyfikacji pliku. Sprawdziłem official java tutorial, ale wciąż mam problemy.Oglądanie katalogu zmian w Javie

Oto kod źródłowy.

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

Jaki system operacyjny i wersja Java? – MadProgrammer

+0

Windows 8 i Java 1.7 – Isuru

+2

Czy wypróbowałeś "stock" [WatchDir.java] (http://docs.oracle.com/javase/tutorial/essential/io/examples/WatchDir.java)? Działa przynajmniej na Linuksie. – user3159253

Odpowiedz

20

Faktycznie niepoprawnie subskrybujesz zdarzenia. Tylko ostatni słuchający został zarejestrowany w typie zdarzeń ENTRY_DELETE.

Aby zarejestrować się do wszelkiego rodzaju imprez należy użyć:

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

Ostrzeżenie! Bezwstydna autopromocja!

Utworzyłem otokę wokół Javy 1.7 WatchService, która umożliwia zarejestrowanie katalogu i dowolnej liczby wzorów glob. Klasa ta będzie dbać o filtrowaniu i tylko emitować zdarzenia, które Cię interesują.

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(); 

Kompletny kod jest w tym Gist.

+0

Awans do kompletnego rozwiązania. Jedno małe zalecenie, ale zauważ, że przykład działa tylko na Java 8. Nie zrozumcie mnie źle, Uwielbiam lambdas, ale Java 7 jest znacznie bardziej powszechna w tych dniach, więc musiałem go doposażyć w Java 7, kiedy go użyłem. Wkrótce opublikuję wersję "naprawioną" dla tych, którzy nie mogą korzystać z Javy 8 jeszcze – nterry

+0

Hej, dziękuję za wkładanie wysiłku. Firma, dla której pracuję, przeszła już na Java 8, ponieważ cykl obsługi Java 7 dobiegł końca. Dlatego nie miałem nieodpartego powodu, by wspierać Javę 7. Zaktualizuję tytuł GIST, aby to odzwierciedlić. – Hindol

+0

Właśnie pobrałem plik ZIP i wypróbowałem go przy użyciu java 1.7. Nie można znaleźć "import java.util.stream" i niektórych "domyślnych" metod. @nterry Czy opublikowałeś wersję Java 7 w dowolnym miejscu? Tnks. – elysch

2

Zrobiłem kilka zajęć dla tego.

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

i

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; 
} 
} 

i

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; 
} 
} 

i

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()); 
     } 
    } 
}