Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java NIO watch Service created both 'ENTRY_CREATE' and 'ENTRY_MODIFY' when a new File is added to the watch folder

I see a strange behaviour ( not sure i this is expected behaviour ) using java.nio.file.WatchService.

The problem is I have a folder registered with WatchService. When I copy a new file into this folder, then two WatchEvent get generated, one each for :

'ENTRY_CREATE' and 'ENTRY_MODIFY'.

As far as I understand, a new file ( copied from other directory which is not getting watched) must create only one event, i.e : 'ENTRY_CREATE'.

Can anybody explain why the extra event 'ENTRY_MODIFY' gets created ?

My code:

public void watch() {
    WatchKey key = watcher.poll();

    //log.info("Watcher scheduler running. Watch key {}", key.hashCode());

    if (key != null) {
        Workflow workflow = keys.get(key);
        log.info("Runing watcher for key '{}'  and workflow {}", key.hashCode(), workflow.getName());
        File hotFolder = new File(workflow.getFolderPath());
        Path dir = hotFolder.toPath();

        for (WatchEvent<?> event : key.pollEvents()) {
            WatchEvent<Path> ev = cast(event);
            Path name = ev.context();
            Path child = dir.resolve(name);

            log.info("Polling event for name {} and child {} and dir {}", name.toFile(), child.toFile(), dir.toFile());

            if (Files.isDirectory(child, LinkOption.NOFOLLOW_LINKS))
                continue;

            try {
                switch (event.kind().name()) {
                case "ENTRY_CREATE":
                    log.info("New file {}", child.toFile());
                    fileService.processNewFile(child.toFile(), workflow);
                    break;
                case "ENTRY_MODIFY":
                    log.info("File modified.... {}", child.toFile());
                    fileService.processModifiedFile(child.toFile(),
                            workflow);
                    break;
                default:
                    log.error("Unknown event {} for file {}", event.kind()
                            .name(), child.toFile());
                    break;
                }
                // Operation op = Operation.from(event.kind());
                // if (op != null)
                // publisher.publishEvent(new FileEvent(child.toFile(),
                // workflow, op));
            } catch (Throwable t) {
                log.warn("Error while procesing file event", t);
            }
        }

        key.reset();
    }
}

So when I copy a file, say name = "abc.txt", the logs display:
New file abc.txt
File modified.... abc.txt


Any inputs is highly solicited.

like image 224
aknon Avatar asked Nov 17 '15 09:11

aknon


2 Answers

Check the "Platform dependencies" section in the WatchService JavaDoc.

The Watcher is behaving correctly in the situation you described. And strictly speaking, when you copy a file to a folder, the files really is CREATED and then MODIFIED.

There are many things to consider when using a WatcherService, its behavior varies a lot with for example:

  • Operating systems
  • Encrypted discs
  • Network shares
  • ...
like image 158
Dainesch Avatar answered Sep 30 '22 00:09

Dainesch


I think, the question has already been answered here.

For instance Java: WatchService gets informed before content is copied

In two words, the events are generated by your operation system. You've got two events which means your OS performs copy in non-atomic way. If you try to read the file somewhere between ENTRY_CREATE and ENTRY_MODIFY, it'll be inconsistent. But again, it depends on your OS. For instance on Windows 7 I'm getting ENTRY_CREATE one time and ENTRY_MODIFY two times for large files. So you actually cannot be sure whether or not the file is successfully copied, you have to come up with application/OS dependent metrics.

like image 43
Kuvaldis Avatar answered Sep 30 '22 02:09

Kuvaldis