Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

File::Monitor problem with batch files

by xbmy (Friar)
on Nov 17, 2010 at 19:31 UTC ( #872039=perlquestion: print w/ replies, xml ) Need Help??
xbmy has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks;

The following code works well for single file, what i want it to do is monitor the mtime of a file, if it has been modified, copy it to a new directory immediately as an automatic backup procedure.

use strict; use warnings; use File::Monitor; use File::Monitor::Object; use File::Copy::Recursive qw(fcopy rcopy dircopy fmove rmove dirmove); my $wFile="1.doc"; my $wFileMonitor = File::Monitor->new(); $wFileMonitor->watch($wFile); $wFileMonitor->scan; while (1){ my @changes = $wFileMonitor->scan; foreach my $object (@changes) { my $modified = $object->mtime; print "$wFile changed\n"; fcopy ("$wFile","c:\\newpath"); # automatic backup if the file h +as been modified } }

But i have many files for which to be monitored, i want to give it a file list or array like the following codes:

use strict; use warnings; use File::Monitor; use File::Monitor::Object; use File::Copy::Recursive qw(fcopy rcopy dircopy fmove rmove dirmove); my @Files=("1.doc","2.doc","3.xls"); my $wFileMonitor = File::Monitor->new(); foreach my $wFile (@Files){ $wFileMonitor->watch($wFile); #-- First scan does nothing $wFileMonitor->scan; while (1){ my @changes = $wFileMonitor->scan; foreach my $object (@changes) { my $modified = $object->mtime; print "$wFile changed\n"; fcopy ("$wFile","c:\\newpath"); } } }

What the codes output is just monitor the first file in the file array or list, when i did some modifies to the other file in the list there was no monitor response. But i want they were monitored simultaneously. Can you give me some advices! Any help will be appreciated!

Comment on File::Monitor problem with batch files
Select or Download Code
Re: File::Monitor problem with batch files
by tokpela (Chaplain) on Nov 17, 2010 at 21:20 UTC

    There are a couple of options.

    One option is to create a thread for each file you want to monitor. If you go this route, check out the Thread::Queue module. You should run a search on this site for many good starting points. BrowserUK has given lots of advise and examples.

    A second option is to monitor a directory and then make a copy if you receive an modification event. There is a module Win32::ReadDirectoryChangesW which will tell you which file was modified and allow you to respond. It is a wrapper around the Win32 API ReadDirectoryChangesW. It is not on CPAN but can be found on this site - so you will need to copy and paste the module into your personal library directory.

    An short example, pieced from how I have used this module (untested).

    use strict; use warnings; use Win32::ReadDirectoryChangesW; my $path = 'c:/directory'; my $subtree = 1; my $filter = FILE_ACTION_ADDED | FILE_ACTION_MODIFIED; my $rdc = Win32::ReadDirectoryChangesW->new(path => $path, subtree => 1, filter => $filter); my @results = $rdc->read_changes; while (scalar @results) { my ($action, $filename) = splice(@results, 0, 2); if ($action == FILE_ACTION_ADDED || $action == FILE_ACTION_MODIFIED +) { # perform your backup here } }

    There is also a third option if you have more than one directory which would be to use both methods 1 and 2.

      Thank you very much! I have setup the win32::readdirectorychangesw module on my hard drive by copying the pm file to the directory of perl. i tried the following code as you told me:

      use strict; use warnings; use File::Copy::Recursive qw(fcopy rcopy dircopy fmove rmove dirmove); use Win32::ReadDirectoryChangesW; my $path = 'c:\\PAPER'; my $subtree = 1; my $filter = FILE_ACTION_ADDED | FILE_ACTION_MODIFIED; my $rdc = Win32::ReadDirectoryChangesW->new(path => $path, subtree => 1, filter => $filter); my @results = $rdc->read_changes; while (scalar @results) { my ($action, $filename) = splice(@results, 0, 2); if ($action == FILE_ACTION_ADDED || $action == FILE_ACTION_MODIFIED +) { # perform your backup here fcopy ("$filename","p:\\phdpaper"); } }

      But i got a wrong message: Bareword "FILE_ACTION_ADDED" not allowed while "strict subs" in use at C:\PAPER\1.pl line 9. Bareword "FILE_ACTION_MODIFIED" not allowed while "strict subs" in use at C:\PAPER\1.pl line 9. Bareword "FILE_ACTION_ADDED" not allowed while "strict subs" in use at C:\PAPER\1.pl line 21. Bareword "FILE_ACTION_MODIFIED" not allowed while "strict subs" in use at C:\PAPER\1.pl line 21. Execution of C:\PAPER\1.pl aborted due to compilation errors.

      Then i delete the "use strict" script, runing...., but still got the following error: Can't locate object method "new" via package "Win32::ReadDirectoryChangesW" (perhaps you forgot to load "Win32::ReadDirectoryChangesW"?) at C:\PAPER\1.pl line 11.

      So, can you help me figure out what the problem was? Thanks a lot!

        Actually, I looked at the module and the package name is

        package Win32::ReadDirectoryChanges;

        The bareword errors were probably because of the incorrect package name. Change the name of the module you copied and pasted to Win32::ReadDirectoryChanges (without the W).

        Try to change the code to:

        use strict; use warnings; use File::Copy::Recursive qw(fcopy rcopy dircopy fmove rmove dirmove); use Win32::ReadDirectoryChanges; my $path = 'c:\\PAPER'; my $subtree = 1; my $filter = FILE_ACTION_ADDED | FILE_ACTION_MODIFIED; my $rdc = Win32::ReadDirectoryChanges->new(path => $path, subtree => 1, filter => $filter); my @results = $rdc->read_changes; while (scalar @results) { my ($action, $filename) = splice(@results, 0, 2); if ($action == FILE_ACTION_ADDED || $action == FILE_ACTION_MODIFIED +) { # perform your backup here fcopy ("$filename","p:\\phdpaper"); } }

Re: File::Monitor problem with batch files
by Illuminatus (Curate) on Nov 17, 2010 at 21:59 UTC
    Have you looked at File::Rsync? It does not require iterative logic to process individual files, and will work either intra- or inter-machine.

    fnord

      You know, I am a newbie for perl programming and really did not look the file::rsync module, maybe i should learn it later.

      I have solved the problem by file::monitor::delta as directed by tokpela (Friar) and Khen1950fx (Prior), thanks to all you guys' help!

Re: File::Monitor problem with batch files
by Khen1950fx (Canon) on Nov 17, 2010 at 23:37 UTC
    I tried it like this:
    #!/usr/bin/perl use strict; use warnings; use File::Monitor; my @Files = qw(1.doc 2.doc 3.xls); my $wFileMonitor = File::Monitor->new(); foreach my $wFile(@Files){ $wFileMonitor->watch($wFile); } $wFileMonitor->scan; my @changes = $wFileMonitor->scan; foreach my $change(@changes) { if ($change->is_mtime) { my $mtime = $change->is_mtine; my $old_mtime = $change->old_mtime; my $new_mtime = $change->new_mtime; print "$mtime has changed mtime from $old_mtime" . "to $new_mtime\n"; } }

      Your code just stop immediately after running, I think it need at least one loop as while (1){ ..... } or something, but after i added the while loop, it still not work for me, it looks like the code i have posted. Thanks anyway!

        It actually was working just as it should work. I called scan twice, so it shut down. I don't think that you need a while loop. For example, you can turn on the monitor, and it will dutifully observe what it's supposed to watch:
        #!/usr/bin/perl use strict; use warnings; use File::Monitor; my @Files = qw(1.doc 2.doc 3.xls); my $wFileMonitor = File::Monitor->new(); foreach my $wFile(@Files){ $wFileMonitor->watch($wFile); } $wFileMonitor->scan;
        Now the monitor is on. It will stay on until you call the second scan---then it reports the changes and shuts off.
Re: File::Monitor problem with batch files
by xbmy (Friar) on Nov 18, 2010 at 22:46 UTC

    Finally, I tried the following code, it works perfectly for monitoring all the files in a directory! Thanks you all!

    use File::Monitor; use File::Copy::Recursive qw(fcopy rcopy dircopy fmove rmove dirmove); my $monitor = File::Monitor->new(); $files= 'c:\\PAPERS'; opendir(AA,$files) || return; my @list = readdir(AA); closedir (AA); foreach $file (@list) { $monitor->watch( $file ); } $monitor->callback( mtime => sub { my ($file, $event, $change) = @_; print "$file has been modified \n\n"; fcopy ("$file","p:\\phdpaper"); } ); while (1) { $monitor->scan; sleep 10; # After the first scan we get a list of File::Monitor::Delta obje +cts # that describe any changes my @changes = $monitor->scan; for my $change (@changes) { # Call methods on File::Monitor::Delta to discover what change +d if ($change->is_mtime) { my $name = $file_name; } } }

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://872039]
Approved by ww
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others examining the Monastery: (4)
As of 2015-07-04 00:14 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (57 votes), past polls