how to monitor the files change in subdirectory?

This code is very good. It can monitor directory change and  the files change in a directory.

Only one issue is it can't monitor the files change in subdirectory. You can see a subdirectory change, but you can't tell which file change in that subdirectory.

Any good idea about this issue?

I really appreciate your help!
use File::Monitor;
use File::Monitor::Object;
 
my $monitor = File::Monitor->new();
 
chdir 'c:\\is';
$temp = 'c:\\dell\test';
 
#watch the files in the directory for changes
foreach (grep {!/^\./} glob("$temp/*")) {
$monitor->watch("$_", sub {
    my ($name, $event, $change) = @_;
    print "$name has been changed.\n";
    });
}
 
#Watch the directory for changes
$monitor->watch( {
        name        => "$temp",
        recurse     => 1,
        callback    => \&Test,
    } );
 
$monitor->scan;
 
for ($i=0; $i < 60; $i++)
{
      my @changes = $monitor->scan;  
      sleep 3;
}
 
sub Test
{
      my ($name, $event, $change) = @_;
 
      my @adds = $change->files_created;
      my @dels = $change->files_deleted;
     
      print "Added: ".join("\nAdded: ", @adds)."\n" if @adds;
      print "Removed: ".join("\nRemoved: ", @dels)."\n" if @dels;
}

Open in new window

howruaz9Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Fairlight2cxCommented:
If you're determined to use this module, I'd probably adjust a few things.

1) Turn off recurse.
2) Do a recursive directory drill-down to collect your directory paths.
3) Set up an instance of the module on each of the harvested paths.  Store each object in an array element.
0
howruaz9Author Commented:

Thank you very much Fairlight2cx.

But I'm a beginner of Perl. This script is what I got from this website and just use it.

Would you please tell me more detail about what you said?

Thanks again for your time and patience.


0
Fairlight2cxCommented:
Actually, I just read the docs for the module you're using.  I know why it's not reporting on the files.  You're missing a setting.  In the above snippet, add a line between line 20 and line 21 that reads:

     files => 1,

That -may- work, or it may not.  The documentation for the "files" option indicates that it should do what you're looking for.  But it seems like it may be mutually exclusive to "recurse".  The documentation is ambiguous at best.  The only way to be sure is to try it out.

If it fails, we can try something else.  I'm not really liking the looks of this module.  Personally, I'd reinvent the wheel from scratch.  There may be no other choice, if the module doesn't do what you want it to.
0
Microsoft Azure 2017

Azure has a changed a lot since it was originally introduce by adding new services and features. Do you know everything you need to about Azure? This course will teach you about the Azure App Service, monitoring and application insights, DevOps, and Team Services.

howruaz9Author Commented:
Fairlight2cx, Thanks so much.

I have tried. But if failed. Nothing showed up about file when that file changed in subdirectory.

I wish I could create another module from scratch. but ...

Anyway thanks very much for your help.

 
0
Adam314Commented:
It doesn't look like File::Monitor will handle the level of detail you need. Here is some code that should work.
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use File::Find;
 
 
##### Your directory to check
my $temp = 'c:\\dell\test';
$temp = '/home/adam/tmp_ee';
 
##### Variable to store data
my %Files;
 
##### Perform initial scan
find(\&Found_Init, $temp);
 
 
##### Search for changes
scan();
 
sub Found_Init {
	my @stat = stat($File::Find::name);
	$Files{$File::Find::name} = [0, -d _, -f _, @stat];
}
 
sub scan {
	$Files{$_}->[0] = 0 foreach (keys %Files);
	find(\&Found_Diff, $temp);
	foreach (keys %Files) {
		next if $Files{$_}->[0];
		print "Removed: $_\n";
	}
}
	
sub Found_Diff {
	my @stat = stat($File::Find::name);
	my $newdata = [0, -d _, -f _, @stat];
	my $newdatav = [1, -d _, -f _, @stat];
	
	if(!exists($Files{$File::Find::name})) {
		print "New file: $File::Find::name\n";
	}
	elsif(join(' ', @$newdata) ne join(' ', @{$Files{$File::Find::name}})) {
		print "Changed: $File::Find::name\n";
	}
	
	$Files{$File::Find::name} = $newdatav;
}

Open in new window

0
Adam314Commented:
Just noticed... remove line 10.  That was for my testing.  You can call scan whenever you want to check for changes.  To match your original code, that would need to be in a loop.  Here is an update.
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use File::Find;
 
 
##### Your directory to check
my $temp = 'c:\\dell\test';
 
##### Variable to store data
my %Files;
 
##### Perform initial scan
find(\&Found_Init, $temp);
 
 
##### Search for changes
for (my $i=0; $i < 60; $i++) {
    scan();
    sleep 3;
}
 
 
sub Found_Init {
	my @stat = stat($File::Find::name);
	$Files{$File::Find::name} = [0, -d _, -f _, @stat];
}
 
sub scan {
	$Files{$_}->[0] = 0 foreach (keys %Files);
	find(\&Found_Diff, $temp);
	foreach (keys %Files) {
		next if $Files{$_}->[0];
		print "Removed: $_\n";
	}
}
	
sub Found_Diff {
	my @stat = stat($File::Find::name);
	my $newdata = [0, -d _, -f _, @stat];
	my $newdatav = [1, -d _, -f _, @stat];
	
	if(!exists($Files{$File::Find::name})) {
		print "New file: $File::Find::name\n";
	}
	elsif(join(' ', @$newdata) ne join(' ', @{$Files{$File::Find::name}})) {
		print "Changed: $File::Find::name\n";
	}
	
	$Files{$File::Find::name} = $newdatav;
}

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
howruaz9Author Commented:
Thanks so much Adam314!  This script is very good.

One small issue is it reported "Removed" every time after scan(); while"New file" and "Changed" only one time.

I want to it report in same way, report just one time after "Changed", "New file", "Removed" or every time it scan.

I have tried many time, but failed. Adam314 Would you please help me again to fix this issue?

I really appreciate your help.

1.bmp
0
Adam314Commented:

sub scan {
        $Files{$_}->[0] = 0 foreach (keys %Files);
        find(\&Found_Diff, $temp);
        foreach (keys %Files) {
                next if $Files{$_}->[0];
                print "Removed: $_\n";
                delete $Files{$_};   #THIS LINE IS NEW
        }
}

Open in new window

0
howruaz9Author Commented:
Adam314, your script is exactly what I need.

Thank you very much for your time and help, really appreciated!
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Perl

From novice to tech pro — start learning today.