Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to monitor a folder for changes in java?

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.

like image 456
Hossein Avatar asked Aug 22 '12 16:08

Hossein


1 Answers

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..

like image 160
pratikabu Avatar answered Oct 24 '22 20:10

pratikabu