1

I need to watch a folder for files- files will drop into folders, and it may take several seconds or a few minutes for the file copy to be complete. I've read multiple topics on SO (Checking File sizes for changes, Detect file in use by other process). Neither of these give a great answer.

Polling is "bad", but how can I know if a file stops increasing in size? Specifically, is there a notification for "file size is constant" or "file is complete"? Can the OS notify of non-activity (IOW, how do you prove a negative?). It would seem to me that logically, one MUST poll a file to see if it's not changing. I've also checked SCEvents and UKKQueue, but again both only notify of a change. UKKQueue has a "file size increased" method, but no "file size has not increased method".

Is there really any way to detect file copy completion without polling or using sleep()?

Community
  • 1
  • 1
Chris Paveglio
  • 527
  • 1
  • 5
  • 17

2 Answers2

1

This is the code I used to monitor file locally. I am not sure if this would work for you.

int fileHander = open("/location/file", O_RDONLY);
  dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
  unsigned long mask = DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_EXTEND | DISPATCH_VNODE_ATTRIB | DISPATCH_VNODE_LINK | DISPATCH_VNODE_RENAME | DISPATCH_VNODE_REVOKE;
  __block dispatch_source_t source;

  void (^changeHandler)(void) = ^{
    unsigned long l = dispatch_source_get_data(source);
    if (l & DISPATCH_VNODE_DELETE) {
      printf("file deleted");
      dispatch_source_cancel(source);
    }
    else {

      printf("file data changed");
    }
  };
  void (^cancelHandler)(void) = ^{
    int fileHander = dispatch_source_get_handle(source);
    close(fileHander);
  };

  source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE,fileHander, mask, queue);
  dispatch_source_set_event_handler(source, changeHandler);
  dispatch_source_set_cancel_handler(source, cancelHandler);
  dispatch_resume(source);
Sandeep
  • 20,908
  • 7
  • 66
  • 106
0

If you have control over the files being delivered, copy them into a temporary directory on the same volume, and when the copy is done, then move the file. The move simply relinks the file in the file system. Then, kqueue can notify you when the file is present. It's presence means the whole file is there.

BTW, when you use the "atomically" version of the cocoa file manager API, this is pretty much what it does behind the scenes.

If you don't have control, and you just want to monitor files, then use kqueue to notify you when a file shows up. As the file grows, queue will notify you that it has been extended. However, it does not know if some other app is done extending the file or not, so you still have to have some sort of timer to check for change.

I would kick off an interval timer at the same time I register for kqueue NOTE_EXTEND events. I would keep track of the last time I saw a NOTE_EXTEND event, and if I had not seen one since the last timer fired, I would assume the file has stopped being extended.

Now, you have to determine what timer value to use... and if you want to back off and keep looking for a "while" but unless the application copying the file does so via a "move" or unless it sends a notification that the file has been fully copied, you are going to have to do some type of timer, with some arbitrary value... at which time you assume it's done.

Obviously, if you can fit into the first option, things are much better as you have a deterministic way of knowing that the file has stopped growing.

Jody Hagins
  • 27,943
  • 6
  • 58
  • 87