【问题标题】:inotify recursively how to do it?inotify 递归地怎么做呢?
【发布时间】:2012-02-05 07:44:54
【问题描述】:

我需要在具有多个子文件夹的文件夹上打印事件。如何递归地做到这一点?请打印 C++ 代码。我被卡住了!!每次弹出 evet 时,我都需要打开子文件夹,获取文件并将其复制到另一个目录中。我不想每 2 秒列出所有子文件夹并查找文件(如果有)。效率不高。我需要使用监视器文件夹。请帮忙

我要监控的导演有多个子文件夹。每个子文件夹都有另一个子文件夹,其中可能包含一个文件。 MainFolder->子文件夹->每个子文件夹->子文件夹->文件。

这是我现在的代码:

/*


*/
  #include <pthread.h>
    #include <unistd.h>

#include <iostream>
#include <sys/inotify.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/inotify.h>
#include <vector>
#include <string>
    #include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
using namespace std;
 vector<string> SS;



void *print_message_function( void *ptr );


int main(int argc, char **argv ){

  pthread_t t1;
    int fd,fd1,wd,wd1,i=0,i1=0,len=0,len1=0;
      int length;
    char pathname[100],buf[1024],buf1[1024];
   int data;
    struct inotify_event *event;
     char *message1 = "Thread 1";



   FILE *fr;
   // fd=inotify_init1(IN_NONBLOCK);//--rewrite
    fd = inotify_init();


    /* watch /test directory for any activity and report it back to me */
    wd=inotify_add_watch(fd,"/home/MainFoder/",IN_ALL_EVENTS);

  //  int flag=0;
   // char*ev="";
//wd=inotifytools_watch_recursively_with_exclude("/home/MainFolder/",IN_ALL_EVENTS);
 while(1)
{
//sleep(30);
        //read 1024  bytes of events from fd into buf

i=0;
        len=read(fd,buf,1024);
        while(i<len){

            event=(struct inotify_event *) &buf[i];


    /* watch /test directory for any activity and report it back to me */


            /* check for changes */
              {
            if((event->mask & IN_OPEN) ||(event->mask & IN_CREATE))

             {  


                 printf("\n %s :was opened\n",event->name);
                SS.push_back(event->name);



             }

       }
            /* update index to start of next event */
            i+=sizeof(struct inotify_event)+event->len;
        }

         vector<string>::const_iterator cii;
for(cii=SS.begin(); cii!=SS.end(); cii++)
       {


wd1 = watch_from_filename(*ci);
}
/*
vector<string>::const_iterator cii;
       for(cii=SS.begin(); cii!=SS.end(); cii++)
       {
          cout <<"HERE:"<< *cii << endl;
       }
*/
int  iret1, iret2;

    /* Create independent threads each of which will execute function */

     iret1 = pthread_create( &t1, NULL, print_message_function, (void*) message1);

}

}
void *print_message_function( void *ptr )
{
    vector<string>::const_iterator cii;
       for(cii=SS.begin(); cii!=SS.end(); cii++)
       {

          cout <<"HERE:"<< *cii << endl;
          std::string path=exec

       }
}

【问题讨论】:

  • 我可以发布代码。请拿出-1票

标签: c++ ubuntu inotify


【解决方案1】:

Github 上的这个工作示例可以满足您的需求:inotify-example.cpp

在 CREATE 事件中,当前 wd(监视描述符)以及 inotify_event wd 和名称组件被添加到 Watch 对象(参见示例)。 该类包括以多种方式查找 wd 和名称的方法。

这个 sn-p 显示了如何处理 CREATE/DELETE 事件:

            if ( event->mask & IN_CREATE ) {
                current_dir = watch.get(event->wd);
                if ( event->mask & IN_ISDIR ) {
                    new_dir = current_dir + "/" + event->name;
                    wd = inotify_add_watch( fd, new_dir.c_str(), WATCH_FLAGS );
                    watch.insert( event->wd, event->name, wd );
                    total_dir_events++;
                    printf( "New directory %s created.\n", new_dir.c_str() );
                } else {
                    total_file_events++;
                    printf( "New file %s/%s created.\n", current_dir.c_str(), event->name );
                }
            } else if ( event->mask & IN_DELETE ) {
                if ( event->mask & IN_ISDIR ) {
                    new_dir = watch.erase( event->wd, event->name, &wd );
                    inotify_rm_watch( fd, wd );
                    total_dir_events--;
                    printf( "Directory %s deleted.\n", new_dir.c_str() );
                } else {
                    current_dir = watch.get(event->wd);
                    total_file_events--;
                    printf( "File %s/%s deleted.\n", current_dir.c_str(), event->name );
                }
            }

【讨论】:

  • 我觉得这里还是有坑的。如果观看 A,然后快速添加 A/B 和 A/B/C,则在您处理 A/B 的通知(并将 B 添加到手表)时,C 已经创建并且您错过了它的创建事件,因为您还没有在 B 上收听。那么你会错过 C 下的任何事件。
  • 同意。不可能足够快地添加目录监视以保证后续文件事件不会丢失。
  • 到目前为止,这是我见过的使用 inotify 的最佳方法。如果您有更好的东西,请分享。有更强大的方法可以通过 Windows 和 OS X 上的日志跟踪文件更改(我相信 *nix 也是如此),但 OP 专门询问了 inotify。
  • 同意彼得,这种方法最适合 inotify。我知道的唯一解决方案是,当观察者的消费者收到目录创建事件时,消费者必须递归扫描该目录并将找到的任何子子目录提交回观察者,以确保观察者有一个为他们打开的句柄。无法以原子方式指定递归手表的不幸副作用,但正如您所说,这是 inotify 实现的不幸产物。
  • 您说得很对,随后扫描新创建的文件夹确实会提高可靠性,但也会增加开销(并且不包括在我的示例中)。如果 OP 需要这种级别的可靠性并且没有特别提到 inotify,我会推荐 fanotify,因为它很健壮并且不会丢失创建事件。
【解决方案2】:

您可以分两步完成:

  1. 检测您对根目录感兴趣的所有更改,以及(如果尚未包括)创建 (IN_CREATE)。
  2. 如果创建的是目录,则对其执行整个算法。

【讨论】:

  • 我已经发布了代码。请告诉我如何改变它?如果创建了第一个子文件夹,我需要通知子文件
  • @user1165435,首先修复您的格式。事实上,它很难阅读。使用一致的间距和大括号样式。除此之外,请尝试执行上述步骤并告诉我们您是否遇到问题。
  • @MatthewFlaschen 感谢您的提示,我实际上正在寻找相同的东西,您的建议很简单而且完全有道理。创建文件夹时,只需 watch() 该文件夹...
【解决方案3】:

我已经为你编写了代码。现在,您只需对该代码进行一次更改。只需在 main 函数中给出您的目录路径即可。

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/inotify.h>
#include <limits.h>
#include<sys/stat.h>
#include<dirent.h>
#include<time.h>
#include<string.h>
#include<unistd.h>

#define MAX_EVENTS 1024 /*Max. number of events to process at one go*/
#define LEN_NAME 16 /*Assuming that the length of the filename won't exceed 16 bytes*/
#define EVENT_SIZE  ( sizeof (struct inotify_event) ) /*size of one event*/
#define BUF_LEN     ( MAX_EVENTS * ( EVENT_SIZE + LEN_NAME )) /*buffer to store the data of events*/

void monitor(char *);
int evnt_mon(char *); 




void main()
{
    if(fork()==0)
    evnt_mon("./usssb");// give path of your directory which you want to monitor
    monitor("./usssb");// give path of your directory which you want to monitor
    while(1);
}

void monitor(char * rt_dir)
{

    struct stat st;
    DIR *dirp; 
    struct dirent *dp;
    char str[100][100]={ };
    char temp[100];
    char str1[500]=" ";
    int i=0,j=0,src_ret=9,src_ret1=9;
    strcpy(str1,rt_dir);
    dirp=opendir(str1);
    if(dirp==NULL)
    {
        perror("opendir");
        return;
    }

    while(1)
    {
        dp=readdir(dirp);
        if(dp==NULL)
        break;
        if((strcmp(dp->d_name,".\0")==0) || (strcmp(dp->d_name,"..")==0))
        continue;   

        if((dp->d_type==DT_DIR)&&((strcmp(dp->d_name,".")!=0)&&(strcmp(dp->d_name,"..")!=0)))
        {   
            strcat(str[i],str1);
            strcat(str[i],"/");
            strcat(str[i],dp->d_name);
            if(fork()==0)   
            {
                evnt_mon(str[i]);
            }
            i++;
        }

    }

    closedir(dirp);
    if(i>0)
    {
        for(j=0;j<i;j++)
        {
            monitor(str[j]);    
        }
    }

}




int evnt_mon(char *argv) 
{
    int length, i = 0, wd;
    int fd;
    char buffer[BUF_LEN];

    /* Initialize Inotify*/
    fd = inotify_init();
    if ( fd < 0 )
    {
        perror( "Couldn't initialize inotify");
    }

    /* add watch to starting directory */
    wd = inotify_add_watch(fd, argv, IN_CREATE | IN_MODIFY | IN_DELETE); 

    if (wd == -1)
    {
        printf("Couldn't add watch to %s\n",argv);
    }
    else
    {
        printf("Watching:: %s\n",argv);
    }

    /* do it forever*/
    while(1)
    {
        i = 0;
        length = read( fd, buffer, BUF_LEN );  
        if ( length < 0 )
        {
            perror( "read" );
        }  

        while ( i < length )
        {
            struct inotify_event *event = ( struct inotify_event * ) &buffer[ i ];
            if ( event->len )
            {
                if ( event->mask & IN_CREATE)
                {
                    if (event->mask & IN_ISDIR)
                    {
                        printf( "The directory %s was Created in %s.\n", event->name,argv );    


                        if(fork()==0)
                        {
                            char p[100]=" ";
                            strcpy(p,argv);
                            strcat(p,"/");
                            strcat(p,event->name);
                            evnt_mon(p);
                        }

                    }                       
                    else
                            printf( "The file %s was Created with WD %d\n", event->name, event->wd );       
                    }

                    if ( event->mask & IN_MODIFY)
                {
                            if (event->mask & IN_ISDIR)
                            printf( "The directory %s was modified.\n", event->name );       
                            else
                            printf( "The file %s was modified with WD %d\n", event->name, event->wd );       
                    }

                    if ( event->mask & IN_DELETE)
                {
                            if (event->mask & IN_ISDIR)
                            printf( "The directory %s was deleted from %s.\n", event->name,argv );       
                            else
                            printf( "The file %s was deleted with WD %d\n", event->name, event->wd );       
                    }  

                i += EVENT_SIZE + event->len;
            }
            }
        }

    /* Clean up*/
    inotify_rm_watch( fd, wd );
    close( fd );

    return 0;
}

【讨论】:

  • 这很好,但有一些错误,例如:如果文件是 shift+delete 然后检测到但如果只删除哪个移动的文件到垃圾箱没有被删除,如果我们从垃圾箱中删除该文件然后没有消息指示。
  • @Rupesh Yadav,你是绝对正确的,但这段代码是为 beaglebone 编写的,我们使用 rm 命令删除它。但我会更新它并尝试解决这个问题。谢谢通知。跨度>
  • while(1); 结尾 main 是个糟糕的主意。将其替换为pause(2)
【解决方案4】:

解决 ribram 所述的问题(“洞”:))。我能想到的一种可能的解决方案是我们可以结合使用“轮询目录”和“使用 inotify”......即每次检测到目录时(仅限目录,不要对文件执行此操作):

  • 为新检测到的目录添加一个观察点以进行 inotify
  • 'poll'(或'scan')新检测到的目录(man readdir())以查看是否已经创建了项目(文件、目录)。这些可能是缺少的。

请注意,要构建“气密”外壳,上述步骤的顺序很重要。您需要先添加观察点而不是扫描...这将保证“扫描”或 inotify 或两者都拾取项目。在这种情况下,您可能还需要了解重复数据。即扫描和inotify都可以产生相同的项目

【讨论】:

    【解决方案5】:

    您可以使用 fanotify API。它允许您监控完整的安装。唯一的缺点是你需要root。

    【讨论】:

      猜你喜欢
      • 2012-05-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-19
      • 2017-08-03
      • 1970-01-01
      相关资源
      最近更新 更多