JPathwatch

JPathwatch

Példaprogram a következő:

 1public class JPathwatchSample {
 2
 3  public static void main(String[] args) throws Exception {
 4    WatchService watchService = FileSystems.getDefault().newWatchService();
 5    Path watchedPath = Paths.get("c:/temp");
 6    WatchEvent.Kind[] eventsToWatch = new WatchEvent.Kind[] {
 7        StandardWatchEventKind.ENTRY_CREATE,
 8        StandardWatchEventKind.ENTRY_DELETE,
 9        StandardWatchEventKind.ENTRY_MODIFY,
10        StandardWatchEventKind.OVERFLOW,
11        ExtendedWatchEventKind.ENTRY_RENAME_FROM,
12        ExtendedWatchEventKind.ENTRY_RENAME_TO,
13    };
14    WatchKey key = null;
15    try {
16      key = watchedPath.register(watchService, eventsToWatch, ExtendedWatchEventModifier.FILE_TREE);
17    }
18    catch (UnsupportedOperationException uox) {
19      System.err.println("file watching not supported!");
20    }
21    catch (IOException iox) {
22      System.err.println("I/O errors");
23    }
24
25    for (;;) {
26      // take() will block until a file has been created/deleted
27      WatchKey signalledKey;
28      try {
29        signalledKey = watchService.take();
30      }
31      catch (InterruptedException ix) {
32        continue;
33      }
34      catch (ClosedWatchServiceException cwse) {
35        System.out.println("watch service closed, terminating.");
36        break;
37      }
38
39      // get list of events from key
40      List<WatchEvent> list = signalledKey.pollEvents();
41
42      // VERY IMPORTANT! call reset() AFTER pollEvents() to allow the
43      // key to be reported again by the watch service
44      signalledKey.reset();
45
46      System.out.println("--------------------------------");
47      // we'll simply print what has happened; real applications
48      // will do something more sensible here
49      for (WatchEvent e : list) {
50        String message = "";
51        if (e.kind() == StandardWatchEventKind.ENTRY_CREATE) {
52          Path context = (Path) e.context();
53          message = context.toString() + " created";
54        }
55        else if (e.kind() == StandardWatchEventKind.ENTRY_DELETE) {
56          Path context = (Path) e.context();
57          message = context.toString() + " deleted";
58        }
59        else if (e.kind() == StandardWatchEventKind.ENTRY_MODIFY) {
60          Path context = (Path) e.context();
61          message = context.toString() + " modified";
62        }
63        else if (e.kind() == ExtendedWatchEventKind.ENTRY_RENAME_FROM) {
64          Path context = (Path) e.context();
65          message = context.toString() + " renamed from";
66        }
67        else if (e.kind() == ExtendedWatchEventKind.ENTRY_RENAME_TO) {
68          Path context = (Path) e.context();
69          message = context.toString() + " renamed to";
70        }
71        else if (e.kind() == StandardWatchEventKind.OVERFLOW) {
72          message = "OVERFLOW: more changes happened than we could retreive";
73        }
74        System.out.println(message);
75      }
76    }
77  }
78}

Jellemzői:

File másolás kezelésére itt készítő tanácsa (FAQ):

Can I use jpathwatch to find out when a program finished writing to a file?

This is a bit tricky, but doable. First of all the problem is that most operating systems do not provide events for that, all they report is if a file has been created, modified or deleted in a directory, which is what jpathwatch passes back to your application code.

So effectively, you can find out when a program writes to a file, but you can’t find out when it’s done with it.

What I recommend in this case is to use heuristics: Assume that a process is done writing to a file when the file isn’t modified for a while (say, ten seconds or so).

Assume you watch a directory on an FTP server, and you want to pick up files after they have finished uploading to that directory.

In a loop, you poll() on the WatchService for events on that directory. For each file that is created or modified (ENTRY_CREATE/ENTRY_MODIFY), you store the time of the last event on that file. Maintain a sorted list of these times; the oldest file in the list is the one that is going to expire first. Remove files that have expired from your sorted list (calculate if their last event time plus the timeout is less than the current time) and flag them as ‘done’.

For the now oldest file in your list that hasn’t expired yet, calculate the time until it will expire, and call poll() with that duration. If you have no more files in your list, call take() instead of poll() to wait for new files to appear.

Az én kis problémámra a következő implementációt hoztam össze.

Másodjára implementálva a megoldást kiderül, hogy a JNotify esetén mely kódrészleteket tudom újra felhasználni. A JNotify-ban megismert BatchExecutor nagyon jól ki lehet emelni. A szemafor váltogatást interfész mögé teszem és már egy csomó mindent nem kell újra megírnom.

 1public interface IWorkerSemafor {
 2  public void working();
 3  public void notWorking();
 4}
 5
 6class BatchExecutor implements Runnable {
 7  private final IWorkerSemafor semafor;
 8
 9  BatchExecutor(IWorkerSemafor semafor) {
10    this.semafor = semafor;
11  }
12
13  @Override
14  public void run() {
15    this.semafor.working();
16    try {
17      Thread.sleep(1 * 1000); // 1 sec
18    }
19    catch (InterruptedException e) {
20      return;
21    }
22    finally {
23      this.semafor.notWorking();
24    }
25    try {
26      System.out.println("executing command... "+new Date());
27      Runtime.getRuntime().exec("cmd /c build.bat ");
28    }
29    catch (IOException e) {
30      e.printStackTrace();
31    }
32  }
33}

És a következő egyszerű kódot írtam, hogy meghajthassam a funkcionalitást:

 1public class JPathwatchSample2 {
 2
 3  public static void main(String[] args) throws Exception {
 4    Thread watcherT = new Thread(watcher);
 5    watcherT.start();
 6    System.out.println("JPathwatch: Press CTR+C to stop");
 7    for (;;) {
 8      Thread.sleep(1000);
 9    }
10  }
11
12  static volatile boolean workerRunning = false;
13
14  static Runnable watcher = new BackgroundWatcher();
15
16  static class BackgroundWatcher implements Runnable, IWorkerSemafor {
17    public void run() {
18      WatchService watchService = FileSystems.getDefault().newWatchService();
19      Path watchedPath = Paths.get("c:/temp");
20      setup(watchService, watchedPath);
21      for (;;) {
22        WatchKey signalledKey;
23        try {
24          signalledKey = watchService.take();
25        }
26        catch (InterruptedException ix) {
27          continue;
28        }
29        catch (ClosedWatchServiceException cwse) {
30          System.out.println("watch service closed, pls exit");
31          break;
32        }
33        List&lt;WatchEvent&lt;?>> list = signalledKey.pollEvents();
34        signalledKey.reset();
35        if (workerRunning) {
36          continue;
37        }
38        if (null == list || 0 == list.size()) {
39          continue;
40        }
41        Thread worker = new Thread(new BatchExecutor(this));
42        worker.start();
43      }
44    }
45    private void setup(WatchService watchService, Path watchedPath) {
46      WatchEvent.Kind<?>[] eventsToWatch = new WatchEvent.Kind[] {
47          StandardWatchEventKind.ENTRY_CREATE,
48          StandardWatchEventKind.ENTRY_DELETE,
49          StandardWatchEventKind.ENTRY_MODIFY,
50          StandardWatchEventKind.OVERFLOW,
51          ExtendedWatchEventKind.ENTRY_RENAME_FROM,
52          ExtendedWatchEventKind.ENTRY_RENAME_TO,
53      };
54      WatchKey key = null;
55      try {
56        key = watchedPath.register(watchService, eventsToWatch, ExtendedWatchEventModifier.FILE_TREE);
57      }
58      catch (UnsupportedOperationException uox) {
59        uox.printStackTrace();
60      }
61      catch (IOException iox) {
62        iox.printStackTrace();
63      }
64    }
65    @Override
66    public void working() {
67      workerRunning = true;
68    }
69    @Override
70    public void notWorking() {
71      workerRunning = false;
72    }
73  };
74}

Directory Watcher
Apr 18, 2012
comments powered by Disqus

Links

Cool

RSS