使用Grand Central Dispatch进行文件监控

时间:2022-03-24 09:01:39

I'm using the code example by David Hamrick to monitor a file using GCD.

我正在使用David Hamrick的代码示例来使用GCD监视文件。

int fildes = open("/path/to/config.plist", O_RDONLY);

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE,fildes, 
                                                  DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_EXTEND | DISPATCH_VNODE_ATTRIB | DISPATCH_VNODE_LINK | DISPATCH_VNODE_RENAME | DISPATCH_VNODE_REVOKE,
                                                  queue);
dispatch_source_set_event_handler(source, ^
{
    //Reload the config file
});
dispatch_source_set_cancel_handler(source, ^
{
    //Handle the cancel
});
dispatch_resume(source);

I want to use to monitor a change of a plist. I get a notification after the first change but not for the following changes. Why?

我想用来监视一个plist的变化。我在第一次更改后收到通知,但没有收到以下更改。为什么?

2 个解决方案

#1


11  

You can indeed just re-open the file and re-register a source (deleting the previous one) when DISPATCH_VNODE_DELETE is received. Or you can use a call which was devised for just this kind of scenario, namely dispatch_io_create_with_path() - that will not only watch by path, it will open the file for you and let you read the contents asynchronously.

您确实可以在收到DISPATCH_VNODE_DELETE时重新打开文件并重新注册源(删除前一个)。或者您可以使用专为此类场景设计的调用,即dispatch_io_create_with_path() - 它不仅会按路径观看,还会为您打开文件并让您以异步方式读取内容。

Since you asked (not sure which technique you asked for, but here's the simplest) here's a stand-alone code sample:

既然你问(不知道你要求哪种技术,但这里最简单)这里有一个独立的代码示例:

#include <dispatch/dispatch.h>
#include <stdio.h>

int main(int ac, char *av[])
{
  int fdes = open("/tmp/pleasewatchthis", O_RDONLY);
  dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
  void (^eventHandler)(void), (^cancelHandler)(void);
  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;

  eventHandler = ^{
    unsigned long l = dispatch_source_get_data(source);
    if (l & DISPATCH_VNODE_DELETE) {
      printf("watched file deleted!  cancelling source\n");
      dispatch_source_cancel(source);
    }
    else {
      // handle the file has data case
      printf("watched file has data\n");
    }
  };
  cancelHandler = ^{
    int fdes = dispatch_source_get_handle(source);
    close(fdes);
    // Wait for new file to exist.
    while ((fdes = open("/tmp/pleasewatchthis", O_RDONLY)) == -1)
      sleep(1);
    printf("re-opened target file in cancel handler\n");
    source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fdes, mask, queue);
    dispatch_source_set_event_handler(source, eventHandler);
    dispatch_source_set_cancel_handler(source, cancelHandler);
    dispatch_resume(source);
  };

  source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE,fdes, mask, queue);
  dispatch_source_set_event_handler(source, eventHandler);
  dispatch_source_set_cancel_handler(source, cancelHandler);
  dispatch_resume(source);
  dispatch_main();
}

#2


1  

After a little bit a research I found out :

经过一番研究后我发现:

=> I was getting the flag DISPATCH_VNODE_DELETE

=>我收到了标志DISPATCH_VNODE_DELETE

I was monitoring ~/Library/Preferences/com.apple.dock.plist As I found out, changing the dock orientation, deletes the original file and replaces it with a new one.

我在监视〜/ Library / Preferences / com.apple.dock.plist正如我所知,更改停靠方向,删除原始文件并用新文件替换它。

Therefore, the monitoring stopped.

因此,监控停止了。

The same author proposes a solution where in case of deletion, the GCD block call itself to continue the monitoring.

同一作者提出了一种解决方案,在删除的情况下,GCD块调用自身继续监视。

#1


11  

You can indeed just re-open the file and re-register a source (deleting the previous one) when DISPATCH_VNODE_DELETE is received. Or you can use a call which was devised for just this kind of scenario, namely dispatch_io_create_with_path() - that will not only watch by path, it will open the file for you and let you read the contents asynchronously.

您确实可以在收到DISPATCH_VNODE_DELETE时重新打开文件并重新注册源(删除前一个)。或者您可以使用专为此类场景设计的调用,即dispatch_io_create_with_path() - 它不仅会按路径观看,还会为您打开文件并让您以异步方式读取内容。

Since you asked (not sure which technique you asked for, but here's the simplest) here's a stand-alone code sample:

既然你问(不知道你要求哪种技术,但这里最简单)这里有一个独立的代码示例:

#include <dispatch/dispatch.h>
#include <stdio.h>

int main(int ac, char *av[])
{
  int fdes = open("/tmp/pleasewatchthis", O_RDONLY);
  dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
  void (^eventHandler)(void), (^cancelHandler)(void);
  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;

  eventHandler = ^{
    unsigned long l = dispatch_source_get_data(source);
    if (l & DISPATCH_VNODE_DELETE) {
      printf("watched file deleted!  cancelling source\n");
      dispatch_source_cancel(source);
    }
    else {
      // handle the file has data case
      printf("watched file has data\n");
    }
  };
  cancelHandler = ^{
    int fdes = dispatch_source_get_handle(source);
    close(fdes);
    // Wait for new file to exist.
    while ((fdes = open("/tmp/pleasewatchthis", O_RDONLY)) == -1)
      sleep(1);
    printf("re-opened target file in cancel handler\n");
    source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fdes, mask, queue);
    dispatch_source_set_event_handler(source, eventHandler);
    dispatch_source_set_cancel_handler(source, cancelHandler);
    dispatch_resume(source);
  };

  source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE,fdes, mask, queue);
  dispatch_source_set_event_handler(source, eventHandler);
  dispatch_source_set_cancel_handler(source, cancelHandler);
  dispatch_resume(source);
  dispatch_main();
}

#2


1  

After a little bit a research I found out :

经过一番研究后我发现:

=> I was getting the flag DISPATCH_VNODE_DELETE

=>我收到了标志DISPATCH_VNODE_DELETE

I was monitoring ~/Library/Preferences/com.apple.dock.plist As I found out, changing the dock orientation, deletes the original file and replaces it with a new one.

我在监视〜/ Library / Preferences / com.apple.dock.plist正如我所知,更改停靠方向,删除原始文件并用新文件替换它。

Therefore, the monitoring stopped.

因此,监控停止了。

The same author proposes a solution where in case of deletion, the GCD block call itself to continue the monitoring.

同一作者提出了一种解决方案,在删除的情况下,GCD块调用自身继续监视。