c++ - linux C++ 通知文件类型创建

标签 c++ c linux inotify

我需要在 Linux 的特定文件夹中监视特定文件类型(具有已知扩展名)的创建。我知道 inotify 只会监视现有文件。我理解正确吗?

是否有 inotify(或类似包)的替代方案允许我按文件类型监控文件创建?

编辑: 我需要的是通过掩码监视文件创建。我需要监视 *.json 的路径,同时忽略其他文件类型。

最佳答案

这听起来像是 inotify 的一个很好的用例。 man page有一个很好的例子,很容易转移到你的问题。

这是一个小程序,可以像这样使用

$ myprog /tmp '*.o' '*.a'

查看目录 /tmp 以创建 *.o*.a 文件。请注意,模式被引用以防止 shell 扩展。程序一直运行直到被 SIGINT 中断(按 Ctrl + C)。

我正在使用 fnmatch 将创建的文件的名称与模式进行匹配,并为设置全局标志的 SIGINT 安装信号处理程序。

#include <assert.h>
#include <errno.h>
#include <fnmatch.h>
#include <limits.h>
#include <signal.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/inotify.h>
#include <unistd.h>

我使用 GCC 的 __attribute__ 扩展定义了一个小的预处理器宏来对齐缓冲区。稍后我们实际使用此宏时会详细介绍。

#ifdef __GNUC__
#  define ALIGNAS(TYPE) __attribute__ ((aligned(__alignof__(TYPE))))
#else
#  define ALIGNAS(TYPE) /* empty */
#endif

这是一个全局标志,我们将在信号处理程序中设置它以指示程序应该正常退出。

static volatile int interrupted = 0;

这是信号处理程序本身。

static void
interruption_handler(const int s)
{
  if (s == SIGINT)
    interrupted = 1;
}

这个函数是程序的主力。

static int
monitor_directory(const char *const directory,
                  const char *const *const patterns,
                  const size_t pattern_count)
{
  int notifyfd = -1;
  int watchfd = -1;
  int ret = 0;
  const char * errmsg = "unknown error";

首先,我们初始化inotifyinotify_init 将返回一个文件描述符,我们可以从中read() 通知。我使用阻塞 I/O,因此 read() 将阻塞直到事件发生。

  notifyfd = inotify_init();
  if (notifyfd < 0)
    {
      errmsg = "inotify_init";
      goto catch;
    }

现在我们注册要观看的文件。在我们的例子中,我们想要监视单个目录 (directory) 以创建新文件 (IN_CREATE)。返回的文件描述符可用于告知(如果事件发生)它属于哪个监视文件。但是,由于无论如何我们只看一个文件(恰好是一个目录),我们真的不需要这个信息。

  watchfd = inotify_add_watch(notifyfd, directory, IN_CREATE);
  if (watchfd < 0)
    {
      errmsg = "inotify_add_watch";
      goto catch;
    }

现在一切都已正确设置,我们可以从通知文件描述符开始 read()ing。

  while (1)
    {

事先不知道从 inotify 描述符调用 read 会读取多少数据,所以我们必须读入一个 char缓冲。我们希望正确对齐它,很难。有关这方面的更多评论,请参见手册页。

      char buffer[sizeof(struct inotify_event) + NAME_MAX + 1] ALIGNAS(struct inotify_event);
      const struct inotify_event * event_ptr;

read() 来自文件描述符。如果我们被打断,read() 将解除阻塞并返回 –1,就像发生错误时一样。

      ssize_t count = read(notifyfd, buffer, sizeof(buffer));
      if (count < 0)
        {
          if (interrupted)
            goto finally;
          errmsg = "read";
          goto catch;
        }

我们有一个新事件,处理它。

      event_ptr = (const struct inotify_event *) buffer;
      assert(event_ptr->wd == watchfd);
      assert(event_ptr->mask & IN_CREATE);
      if (event_ptr->len)
        {
          size_t i;

尝试将文件名与我们的每个模式进行匹配。

          for (i = 0; i < pattern_count; ++i)
            {
              switch (fnmatch(patterns[i], event_ptr->name, FNM_PATHNAME))
                {
                case 0:
                  /* Your application logic here... */
                  if (printf("%s\n", event_ptr->name) < 0)
                    {
                      errmsg = "printf";
                      goto catch;
                    }
                  break;
                case FNM_NOMATCH:
                  break;
                default:
                  errmsg = "fnmatch";
                  goto catch;
                }
            }
        }
    }

最后,我们必须做一些清理工作。 close()关闭由 inotify 创建的文件描述符将导致它释放所有关联的资源。

 finally:
  if (watchfd >= 0)
    {
      int status = close(watchfd);
      watchfd = -1;
      if (status < 0)
        {
          errmsg = "close(watchfd)";
          goto catch;
        }
    }
  if (notifyfd >= 0)
    {
      int status = close(notifyfd);
      notifyfd = -1;
      if (status < 0)
        {
          errmsg = "close(notifyfd)";
          goto catch;
        }
    }
  return ret;
 catch:
  if (errmsg && errno)
    perror(errmsg);
  ret = -1;
  goto finally;
}

这就是我们将所有内容连接在一起并运行程序的方式。

int
main(const int argc, const char *const *const argv)
{
  if (argc < 3)
    {
      fprintf(stderr, "usage: %s DIRECTORY PATTERN...\n", argv[0]);
      return EXIT_FAILURE;
    }
  {
    struct sigaction sa;
    sa.sa_handler = interruption_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGINT, &sa, NULL);
  }
  if (monitor_directory(argv[1], argv + 2, argc - 2) < 0)
    return EXIT_FAILURE;
  return EXIT_SUCCESS;
}

关于c++ - linux C++ 通知文件类型创建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28455484/

相关文章:

linux - 挂载RootFS错误: VFS: Cannot open root device "mtdblock4" or unknown-block(0, 0)

c++ - IE 地址栏搜索。我需要在当前结果列表的末尾添加其他结果列表

c++ - 如何在C++中重载[arg]两个参数的函数?

c - scanf() 无限运行,程序在一条语句上停止运行

C 语言计算

c++ - 如何使用 Qt C++ 从 linux 桌面环境获取当前主题名称

c++ - 在 C++ 中更改全局变量

c++ - 数据结构为 "intrusive"意味着什么?

c - 并行操作执行时间因分配动态内存与静态内存而异

python - 树莓派 : terminate raspistill command from python