8

I've tried to copy&paste a very small file into a folder which is observed by a watch service. The first time works great, but on all following copy&paste actions, i get an exception that another process handles the file already. With experiments I've found out that my service is informed when Windows creates the file and not when its content is copied. If I lock the file, Windows isn't able to copy any data and the file is empty. On the other hand, if I move the file into the directory, everything works fine.

Is that a bug from Windows? I wasn't able to test it on a mac or Linux workstation. Or maybe it was just me being incapable. Any help is appreciated.

My code looks like the following:

try (WatchService watchService = importPath.getFileSystem().newWatchService()) {
  importPath.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);
  handleExistingFiles();

  try {
    do {
      WatchKey watchKey = watchService.take();
      if (!watchKey.isValid()) {
        continue;
      }

      boolean hasCreationEvents = false;
      for (WatchEvent<?> event : watchKey.pollEvents()) {
        hasCreationEvents |= event.kind().equals(StandardWatchEventKinds.ENTRY_CREATE);
      }
      watchKey.reset();

      if (hasCreationEvents) {
        handleNewFiles();
      }
    }
    while (!Thread.currentThread().isInterrupted());
  }
  catch (InterruptedException ignoredEx) {
    Thread.currentThread().interrupt();
  }
}
Teazl
  • 233
  • 3
  • 12
  • And what program(s) create the file that you watch? Do not forget that more often than not, programs write to a temporary file and _only then_ overwrite the original – fge Apr 09 '14 at 08:14
  • Its an older program of ours which creates an output file to transmit data to the current one. I will check how the file gets written, but as Oleg mentioned below, it just might be a problem that two events occur, one for the creation and one for the modification and I responded to the wrong one... – Teazl Apr 09 '14 at 08:53

1 Answers1

10

The copy operation is not always atomic.

With atomic copy (or move) you will get a single ENTRY_CREATE event and the file referenced by the event will be complete and available for reading.

If the copy is not atomic, you will receive an ENTRY_CREATE event when the file is created and then you will receive one or more ENTRY_MODIFY events while the file is being written by the copy operation.

There is no easy way to determine when the copy operation has finished writing to a file and released it. Depending on the OS and file system you could get FileNotFoundException when trying to open a file for reading while it is locked by the copy operation or you could successfully open a file but you will get partial contents when you actually read it.

You will have to implement some heuristics like trying to read a file immediately after ENTRY_CREATE and rescheduling the reading for some later time if the initial reading failed.

Oleg Estekhin
  • 8,063
  • 5
  • 49
  • 52
  • 1
    Thanks for the hint. I changed the code from ENTRY_CREATE to ENTRY_MODIFY and witnessed no problems at all, at least with windows. I will check it with the other operating systems and hope that it will work there too. After I've processed the file, it will be deleted anyway. I guess that will do the trick :) – Teazl Apr 09 '14 at 08:51
  • I was able to test it on a MAC system. It works there too. Thanks a lot! *yay* – Teazl Apr 09 '14 at 11:25