I have bellow code to monitor a directory for any file changes.
public class DirectoryWatcherExample {
public static void main(String[] args) {
WatchService watchService
= FileSystems.getDefault().newWatchService();
Path path = Paths.get(System.getProperty("user.home"));
path.register(
watchService,
StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_DELETE,
StandardWatchEventKinds.ENTRY_MODIFY);
WatchKey key;
while ((key = watchService.take()) != null) {
for (WatchEvent<?> event : key.pollEvents()) {
System.out.println(
"Event kind:" + event.kind()
+ ". File affected: " + event.context() + ".");
}
key.reset();
}
}
}
Currently this is a stand alone and is being executed from my eclipse IDE. Now I need to automate it and I should not run this class everytime. Would you please help me as to how I can remove main() method and run it? Can I create a exeucutable jar and run it? If i run it once then will the program continuosly listen the directlroy? When will the program stops listening the directory? Is there any time limit, I mean after a few days?
Related
Since Java 1.7 there is a way of watching directory without adding additional libraries. On Oracle site there is a little tutorial how to use the WatchService http://docs.oracle.com/javase/tutorial/essential/io/notification.html#try but it is highly not understandable to me. There is no consitent example how to use it.
Therefore would someone kindly show me how to to add listener to directory and invoke method for example: f() when the file is added to directory let's say :"./folder" ?
This piece of code will be called every time you create a file in your watched folder:
Path path = new File("./folder").toPath();
WatchService watchService = FileSystems.getDefault().newWatchService();
path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);
for (;;) {
try {
WatchKey key = watchService.take();
for (WatchEvent<?> event : key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
if (kind.equals(StandardWatchEventKinds.ENTRY_CREATE)) {
System.out.println("file created");
}
}
} catch (InterruptedException x) {
return;
}
}
I'm trying to develop a watch service that, every time a piece of code is modifed, created or deleted, does a certain action.
I've made a Daemon that implements WatchService and that gets the path to a certain package to watch, for example "../JDV/src/randompackage/java/test/money_scenario".
This Daemon has the following code:
public Daemon(Path dir) throws IOException{
this.dir = dir;
watcher = FileSystems.getDefault().newWatchService();
WatchKey key = dir.register(watcher, ENTRY_CREATE,ENTRY_DELETE,
ENTRY_MODIFY);
}
public void processEvents() throws InitializationError {
for (;;) {
// wait for key to be signaled
WatchKey key;
try {
key = watcher.take();
} catch (InterruptedException x) {
return;
}
for (WatchEvent<?> event: key.pollEvents()) {
WatchEvent.Kind kind = event.kind();
if (kind == OVERFLOW) {
continue;
}
if(kind == ENTRY_CREATE) {
System.out.println("Creation has been detected in " + getDirName());
}
if(kind == ENTRY_DELETE) {
System.out.println("Deletion has been detected in " + getDirName());
}
if(kind == ENTRY_MODIFY) {
System.out.println("Modification has been detected in " + getDirName());
}
}
boolean valid = key.reset();
if (!valid) {
break;
}
}
}
What happens is the following: I run the Daemon and it is active. Whenever I go Create or Delete a class in in the money_scenario package (which itselves has subpackages from where I could delete/create the class), the Daemon detects it and prints "Modification has been detected", instead of creation/deletion. When I modify a class in the money_scenario package, it doesn't detect anything.
What am I doing wrong?
Edit: Resolved but another issue popped up. Multiple events:
When I delete a class for example I get:
Modification has been detected in money_scenario
Deletion has been detected in money_scenario
Modification has been detected in money_scenario
I'm really not sure what to tell you on this one, because I took your code and it ran fine on my machine.
The only thing I removed was the throws InitializationError, though I doubt that it has something to do with it.
Config: Mac OS X 10.9/Java 1.7.0_45/Intellij IDEA 12.1.6
P.S.
which itselves has subpackages from where I could delete/create the class
WatchService only watches the directory that you point to, if you want to watch the subdirectories you need to recursively walk and register each directory in the subtree.
EDIT:
public void processEvents() {
boolean finished = false;
while (!finished) {
// wait for key to be signaled
WatchKey key;
try {
key = watcher.take();
} catch (InterruptedException x) {
return;
}
for (WatchEvent<?> event : key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
switch (kind.name()) {
case "ENTRY_CREATE":
System.out.println("Creation has been detected in " + getDirName());
break;
case "ENTRY_DELETE":
System.out.println("Deletion has been detected in " + getDirName());
break;
case "ENTRY_MODIFY":
System.out.println("Modification has been detected in " + getDirName());
break;
default:
continue;
}
if (!key.reset()) {
finished = true;
}
}
}
}
Im watching a directory using Java 7 nio WatchService by using below method.
Path myDir = Paths.get("/rootDir");
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.context().toString());
JOptionPane.showMessageDialog(null,"Created: " + event.context().toString());
}
if (event.kind() == StandardWatchEventKinds.ENTRY_DELETE) {
System.out.println("Delete: " + event.context().toString());
JOptionPane.showMessageDialog(null,"Delete: " + event.context().toString());
}
if (event.kind() == StandardWatchEventKinds.ENTRY_MODIFY) {
System.out.println("Modify: " + event.context().toString());
JOptionPane.showMessageDialog(null,"Modify: " + event.context().toString());
}
}
} catch (Exception e) {
System.out.println("Error: " + e.toString());
}
But the above method only respond in one events happen in the directory after that watcher does not respond to the events happen in that folder. Is there a way that I can modify this to capture all events happen inside the folder. I also want to modify this to capture events happen in sub folders too. Can someone help me with that.
Thank you.
From the JavaDoc of WatchService:
A Watchable object is registered with a watch service by invoking its register method, returning a WatchKey to represent the registration. When an event for an object is detected the key is signalled, and if not currently signalled, it is queued to the watch service so that it can be retrieved by consumers that invoke the poll or take methods to retrieve keys and process events. Once the events have been processed the consumer invokes the key's reset method to reset the key which allows the key to be signalled and re-queued with further events.
You are only calling watcher.take() once.
To watch for further events, you must call watchKey.reset() after consuming the WatchEvents. Put all this in a loop.
while (true) {
WatchKey watckKey = watcher.take();
List<WatchEvent<?>> events = watckKey.pollEvents();
for (WatchEvent event : events) {
// process event
}
watchKey.reset();
}
Also take a look at the relevant section of the Java Tutorial.
Use Apache Commons IO File Monitoring
it will also capture events happening in sub folders too
import java.io.File;
import java.io.IOException;
import org.apache.commons.io.monitor.FileAlterationListener;
import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
import org.apache.commons.io.monitor.FileAlterationMonitor;
import org.apache.commons.io.monitor.FileAlterationObserver;
public class Monitor {
public Monitor() {
}
//path to a folder you are monitoring .
public static final String FOLDER = MYPATH;
public static void main(String[] args) throws Exception {
System.out.println("monitoring started");
// The monitor will perform polling on the folder every 5 seconds
final long pollingInterval = 5 * 1000;
File folder = new File(FOLDER);
if (!folder.exists()) {
// Test to see if monitored folder exists
throw new RuntimeException("Directory not found: " + FOLDER);
}
FileAlterationObserver observer = new FileAlterationObserver(folder);
FileAlterationMonitor monitor =
new FileAlterationMonitor(pollingInterval);
FileAlterationListener listener = new FileAlterationListenerAdaptor() {
// Is triggered when a file is created in the monitored folder
#Override
public void onFileCreate(File file) {
// "file" is the reference to the newly created file
System.out.println("File created: "+ file.getCanonicalPath());
}
// Is triggered when a file is deleted from the monitored folder
#Override
public void onFileDelete(File file) {
try {
// "file" is the reference to the removed file
System.out.println("File removed: "+ file.getCanonicalPath());
// "file" does not exists anymore in the location
System.out.println("File still exists in location: "+ file.exists());
} catch (IOException e) {
e.printStackTrace(System.err);
}
}
};
observer.addListener(listener);
monitor.addObserver(observer);
monitor.start();
}
}
I have make some code for detect changed in directory C:/java/newfolder it working good. i have given below.
import java.nio.file.*;
import java.util.List;
public class DirectoryWatchExample {
public static void testForDirectoryChange(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.context().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());
}
}
public static void main (String[] args) {
Path myDir = Paths.get("c:/java/newfolder/");
//define a folder root
testForDirectoryChange(myDir);
}
}
now i watching only the directory. But i need to watch only the all sub directory.
for ex : c:/java/newfolder/folder1, c:/java/newfolder/folder2, c:/java/newfolder/folder3......etc
i given examples above sub directory
c:/java/newfolder/*..
i need to watch the all sub directory give me some solutions ?
What you want to do is register the WatchService recursively and continue to register it upon subsequent ENTRY_CREATE events. A complete example is provided by Oracle here: http://docs.oracle.com/javase/tutorial/essential/io/examples/WatchDir.java
Normally I wouldn't place a post with a single link, however I doubt Oracle will be taking down a fairly basic tutorial and the answer is far too verbose. Just in case though, examples are easily found by searching for "java watchservice recursive".
Here is what I came with..
final WatchService watcher = FileSystems.getDefault().newWatchService();
final SimpleFileVisitor<Path> fileVisitor = new SimpleFileVisitor<Path>(){
#Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException
{
dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
return FileVisitResult.CONTINUE;
}
};
Files.walkFileTree(Paths.get("/directory/to/monitor"), fileVisitor);
I'm not familiar with the Path API, so take the following with a grain of salt.
You're registering one directory for monitoring, and will receive notifications whenever one of its direct descendants is modified / created / deleted.
The first thing you need to do is register all of its subdirectories for watching:
// Used to filter out non-directory files.
// This might need to filter '.' and '..' out, not sure whether they're returned.
public class DirectoryFilter implements FileFilter {
public boolean accept(File file) {
return file.isDirectory();
}
}
// Add this at the end of your testForDirectoryChange method
for(File dir: myDir.toFile().listFiles(new DirectoryFilter())) {
testForDirectoryChange(dir.toPath());
}
This will recursively explore your file structure and register every directory for watching.
Note that if your directory tree is too deep, recursion might not be an acceptable solution and you might need to 'iterify' it.
The second thing you need to do is, whenever you receive a directory creation event, not forget to register the new directory for monitoring.
That's how I'd do it anyway, but not having a valid Java 1.7 installation at hand, I can't test it. Do let me know if it works!
So what you want is listing the files/subdirectories within a directory?
You can use:
File dir = new File("c:/java/newfolder/");
File[] files = dir.listFiles();
listFiles() gives you the Files in a directory or null it it's not a directory.
Then you can do:
for (File file: files){
if (file.listFiles != null){
//It's a subdirectory
File [] subdirFiles = file.listfiles;
}
}
I want to fire an event whenever a file has stopped being modified. I am polling a directory and if the filename matches to "input.csv" then i want to fire an event on that file. Time to check whether the file has been modified is 10 seconds. I am getting a null pointer exception when no event occurs.
This is my sample code:
public class MyPoller {
public static void main(String[] args) throws URISyntaxException,
IOException, InterruptedException {
Path tmpPath = Paths.get("E:/MyDirectory/DEC");
WatchService watchService = FileSystems.getDefault().newWatchService();
// Watching the E:/MyDirectory/DEC directory
// for MODIFY and DELETE operations
tmpPath.register(watcput.csvService, StandardWatchEventKinds.ENTRY_MODIFY,
StandardWatchEventKinds.ENTRY_DELETE);
for (;;) {
WatchKey key = watchService.poll(10000,TimeUnit.MILLISECONDS);
List<WatchEvent<?>> events = key.pollEvents();
// Poll all the events queued for the key
for (WatchEvent event : events) {
switch (event.context().toString()) {
case "input.csv":
System.out.println("Modified: " + event.context());
String filename = "" + event.context();
System.out.println(" "+filename);
break;
default:
break;
}
}
boolean valid = key.reset();
// If the key is invalid, just exit.
if (!valid) {
break;
}
}
}
}
If no event is generated, then the WatchKey may be null
WatchKey key = watchService.poll(10000,TimeUnit.MILLISECONDS);
Try to do a null check on the key and then proceed to do pollEvents() if it's indeed not null.