Solved

how to monitor the files change in subdirectory?

Posted on 2009-07-10
9
353 Views
Last Modified: 2012-08-13
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

0
Comment
Question by:howruaz9
  • 4
  • 3
  • 2
9 Comments
 
LVL 7

Expert Comment

by:Fairlight2cx
ID: 24828974
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
 

Author Comment

by:howruaz9
ID: 24830402

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
 
LVL 7

Assisted Solution

by:Fairlight2cx
Fairlight2cx earned 100 total points
ID: 24830570
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
 

Author Comment

by:howruaz9
ID: 24831451
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
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
LVL 39

Expert Comment

by:Adam314
ID: 24841386
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
 
LVL 39

Accepted Solution

by:
Adam314 earned 400 total points
ID: 24841400
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
 

Author Comment

by:howruaz9
ID: 24845830
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
 
LVL 39

Assisted Solution

by:Adam314
Adam314 earned 400 total points
ID: 24846341

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
 

Author Closing Comment

by:howruaz9
ID: 31602349
Adam314, your script is exactly what I need.

Thank you very much for your time and help, really appreciated!
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Email validation in proper way is  very important validation required in any web pages. This code is self explainable except that Regular Expression which I used for pattern matching. I originally published as a thread on my website : http://www…
I have been pestered over the years to produce and distribute regular data extracts, and often the request have explicitly requested the data be emailed as an Excel attachement; specifically Excel, as it appears: CSV files confuse (no Red or Green h…
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
This Micro Tutorial hows how you can integrate  Mac OSX to a Windows Active Directory Domain. Apple has made it easy to allow users to bind their macs to a windows domain with relative ease. The following video show how to bind OSX Mavericks to …

867 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now