pearlie has asked for the wisdom of the Perl Monks concerning the following question:

Hello All, I want to know whether a file has actually been modified by using Tie::File or not in my script. I have used tie and want to know the status of the file after untie. Is there any other way to know this apart from looking at the modification time of the file?

Replies are listed 'Best First'.
Re: tie::file - file modification status
by Random_Walk (Prior) on Feb 09, 2005 at 16:42 UTC

    OK, I think I got it working. forget Tie::Watch, I could not get that to work (though I am sure it can be made to) but I have created a little package called Sensitive_Array. this will set a global variable when the watched array is altered, dirty I know but that's the way the code grew. It also prints out the methods being called. I did not implement it all, but more than enough for this example.

    Make @watched_array the array your code is using, do not touch @array directly

    First the test code

    #!/usr/bin/perl use strict; use warnings; use Tie::File; use Sensitive_Array; # this is the global var I am using $main::touched=0; my (@array, @watched_array); my $file='test_tie_file'; # First tie the array to the file tie @array, 'Tie::File', $file or die "cannot tie to $file: $!\n"; push @array, int (rand 1000) until $#array > 39; # fill it on the firs +t pass # now tie it up to an array that will tell us when it was altered tie @watched_array, 'Sensitive_Array', \@array; print "array of length $#watched_array is now watched\n"; print "would you like to alter the file (y/n)\n"; my $ansa=<STDIN>; push @watched_array, 'touched' if $ansa =~/^y/; untie @array; if ($main::touched) { print "File has been altered\n" } else { print "File remains the same\n"; }
    And here is the package, it is heavily borrowed from the example in the tie documentation here is the output
    C:\PERL\bin>perl tie_test Fetchsize array of length 47 is now watched would you like to alter the file (y/n) y Push Fetchsize File has been altered C:\PERL\bin>perl tie_test Fetchsize array of length 48 is now watched would you like to alter the file (y/n) n File remains the same

    Cheers,
    R.

    Pereant, qui ante nos nostra dixerunt!
Re: tie::file - file modification status
by Random_Walk (Prior) on Feb 09, 2005 at 13:19 UTC

    I guess you can not do the obvious and patch in a flag to your code that is flipped by the same logic that decides whether to alter the tied array ?

    use Tie::File; tie @array, 'Tie::File', filename or die ...; if ($something) { push @array, $something_else $file_altered++; }

    Another other way would be to use Tie::Watch to notify you if changes are made to the file tied array. I am assuming you can chain these two together, will try some test code myself and report back later if I get time.

    you could also do an MD5 hash of your tied array when you first open it and compare this to one before you untie it. This is going to be a lot more costly than comparing the modification times.

    Update

    OK I have tried Tie::Watch and Tie::Array together and it looks like they do not chain. Whichever is done last is the only one in effect. My code is below in case a wiser monk than I can point out my error. It may still be possible to create a new array in place of the original, Tie::Watch it and have the methods in Tie::Watch call the appropriate update to the Tie::File array. Without further ado here is my test.
    #!/usr/bin/perl use strict; use warnings; use Tie::File; use Tie::Watch; $main::touched=0; my @array; my $file='test_tie_file'; sub touched {$main::touched=1} push @array, int (rand 1000) until $#array > 39; # fill it on the firs +t pass my $watch = Tie::Watch->new( -variable => \@array, -debug => 0, -shadow => 1, -fetch => sub {print "Fetch\n"; my $self=shift; $self->Fetch}, -store => sub {print "Store\n"; $main::touched=1; my $self=shift; $self->Store (@_)}, -push => sub {print "Push\n"; $main::touched=1; my $self=shift; $self->Push (@_)}, -clear => sub {print "Clear\n"; $main::touched=1; my $self=shift; $self->Clear (@_)}, -extend => sub {print "Extend\n"; $main::touched=1; my $self=shift; $self->Extend (@_)}, ); tie @array, 'Tie::File', $file or die "cannot tie to $file: $!\n"; $main::touched=0; print "array of length $#array is now watched\n"; print "would you like to alter the file (y/n)\n"; my $ansa=<STDIN>; push @array, 'touched' if $ansa =~/^y/; untie @array; $watch->Unwatch; if ($main::touched) { print "File has been altered\n" } else { print "File remains the same\n"; }

    Cheers,
    R.

    Pereant, qui ante nos nostra dixerunt!