7

I have the below code for monitoring a folder for any changes in java:

    public class FolderWatcher
    {
    // public List<Event> events = new ArrayList<Event>();

    public static Event call() throws IOException, InterruptedException
    {
        LOG.info("Watching folder");
        Path _directotyToWatch = Paths.get("data/input-files"); // this will be put in the configuration file
        WatchService watcherSvc = FileSystems.getDefault().newWatchService();
        WatchKey watchKey = _directotyToWatch.register(watcherSvc,  ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);

        watchKey = watcherSvc.take();
        for (WatchEvent<?> event : watchKey.pollEvents())
        {
            WatchEvent<Path> watchEvent = castEvent(event);
            LOG.info(event.kind().name().toString() + " " + _directotyToWatch.resolve(watchEvent.context()));
            String eventName = event.kind().name();
            String fileName = _directotyToWatch.resolve(watchEvent.context()).toString();
            watchKey.reset();
            return new Event(eventName, fileName);
        }
        return null;

    }

@SuppressWarnings("unchecked")
static <T> WatchEvent<T> castEvent(WatchEvent<?> event)
{
    return (WatchEvent<T>) event;
}

}

and:

public abstract class AbstractWatcher
{
    abstract void eventDetected(Event event);

    private final ScheduledExecutorService threadpool;

    public AbstractWatcher(ScheduledExecutorService threadpool)
    {
        this.threadpool = threadpool;
    }

    public AbstractWatcher()
    {
        threadpool = Executors.newSingleThreadScheduledExecutor();
    }


    public void handle()
    {
        final FolderWatcherHandler handler = new FolderWatcherHandler();

        final Runnable r = new Runnable()
        {
            @Override
            public void run()
            {
                try
                {
                    Event event = FolderWatcher.call();
                    if (event != null)
                    {
                        handler.eventDetected(event);
                    }
                }
                catch (IOException e)
                {
                        LOG.error("failed to watch the update", e);
                 }
                catch (InterruptedException e)
                {
                    LOG.info("thread interrupted", e);
                    Thread.currentThread().interrupt();
                    return;
                }

            }
        };

        Runtime.getRuntime().addShutdownHook(new Thread()
        {
            @Override
            public void run()
            {
                    threadpool.shutdown();

            }
        });

        threadpool.scheduleWithFixedDelay(r, 0, 1, TimeUnit.NANOSECONDS);
    }
}

and:

public class FolderWatcherHandler extends AbstractWatcher
{
    @Override
    public void eventDetected(Event event)
    {
         // Do stuff
        }
}

This whole thing works perfect as long as modifications of files(in my case mostly adding) is done 1 by 1 with a small delay within each addition. However, if I drag and drop, or add several files at the same time. This code only detects the event for the first file and not the rest. I even put the excecution time in Nanoseconds but it didn't help. I am wondering of this whole code is a currect way of doing this. Can someone help me. thanks.

Hossein
  • 40,161
  • 57
  • 141
  • 175
  • You can have a look at Java NIO.2 available since Java SE 7 : http://docs.oracle.com/javase/tutorial/essential/io/notification.html – Alexandre Dupriez Aug 22 '12 at 16:41
  • Similar Thread http://stackoverflow.com/questions/1286114/detecting-moved-files-using-filesystemwatcher – Mike Aug 22 '12 at 16:43
  • @AlexandreDupriez This should be an answer, I think (even if I'm sure I saw a similar question in java recently) – Denys Séguret Aug 22 '12 at 16:46
  • Is that a duplicate enough ? http://stackoverflow.com/questions/3810790/is-it-possible-to-monitor-folder-using-java-code – Denys Séguret Aug 22 '12 at 16:48
  • is the OP using jPathWatcher, a third party library? – Naidu Ypvs Aug 22 '12 at 18:19
  • @AlexandreDupriez: the main code is from the java 7 NIO example, I modified it a bit(removing the while(true) and instead turninng everything using an event handler) – Hossein Aug 22 '12 at 18:47
  • @NaiduYpvs: no I am using normal Java 7 libraries – Hossein Aug 22 '12 at 18:47
  • Hossein, once I saw exactly what API you are using, it became clear that the endless loop that you had earlier is the right approach. This is because the `WatchService` is already by itself an event-oriented API and the method `take` blocks until the next event is available. – Marko Topolnik Aug 23 '12 at 09:01
  • @MarkoTopolnik thanks. In that case the approach you told me the other day is not a suitable approach for this specific case, now I use Observer/Observable approach to deal with it and it works perfect! – Hossein Aug 23 '12 at 12:56

2 Answers2

1

Why don't you store a metadata file in each folder (recursively), in that metadata file you can store file list and modified date and size of each file. Your thread should compare this metadata file in each folder with the current files present in the same. That is how you can detect any change within that folder.

Remember you should do it recursively for each subfolder within that. And the metadata file should be updated with each scan. Hope this helps..

pratikabu
  • 1,672
  • 14
  • 17
  • This method doesn't work for me. Files are supposed to be add/modified outside of the application. Then how would i write the metedata?? – Hossein Aug 22 '12 at 18:49
  • In that case store those `metadata` files within your **application's temp location**. Maintain a hierarchy of all the `subfolders` within that `metadata` file. will that work? – pratikabu Aug 22 '12 at 19:00
  • However this method isn't foolproof. – Pacerier Oct 20 '14 at 10:57
0

in my case, this code was successfull:

try {
    Path rootFolder = Paths.get(ctxProperties.getProperty("rootFolder"));
    WatchService watcher = rootFolder.getFileSystem().newWatchService();
    rootFolder.register(watcher, StandardWatchEventKinds.ENTRY_CREATE);
    while (true) {
        WatchKey watchKey = watcher.take();
        if (watchKey != null) {
            for (WatchEvent event : watchKey.pollEvents()) {
                if (StandardWatchEventKinds.ENTRY_CREATE.equals(event.kind())) {
                    String fileName = rootFolder.toString() + "/" + event.context().toString();
                    String messageStr = convertFileToString(fileName);
                    if (messageStr != null) {
                        try {
                            sendMessage(jmsPublisher, messageStr, getJmsProperties());
                            moveMessageToProcessedDirectory(fileName, ctxProperties.getProperty("successFolder"), ".ok");
                            LOGGER.info("JMS message successfully sent");
    sleep(Long.parseLong(ctxProperties.getProperty("sleepBetweenMsgMse")));
                        } catch (Exception e) {
                            moveMessageToProcessedDirectory(fileName, ctxProperties.getProperty("errorFolder"), ".nok");
                        }
                    } else {
                        LOGGER.error("ERROR: error parsing file content to string with file: " + fileName);
                        moveMessageToProcessedDirectory(fileName, ctxProperties.getProperty("errorFolder"), ".nok");
                    }
                }
            }
            boolean valid = watchKey.reset();
            if (!valid) {
                LOGGER.error("ERROR: the watcher is no longer valid, the directory is inaccessible");
                break;
            }
        } else {
            LOGGER.error("ERROR: the watcher is null or not watchable");
            break;
        }
    }
} catch (InterruptedException interruptedException) {
    LOGGER.error("InterruptedException: thread got interrupted",interruptedException);
} catch (Exception exception) {
    LOGGER.error("Exception: " + exception.getMessage(), exception);
}
  • 1
    Welcome to Stack Overflow! While this code snippet may be the solution, [including an explanation](//meta.stackexchange.com/questions/114762/explaining-entirely-‌​code-based-answers) really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – Johan Jun 13 '19 at 09:58