Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

File::Tail on win32

by perlAffen (Sexton)
on Nov 29, 2005 at 22:45 UTC ( [id://512791]=perlquestion: print w/replies, xml ) Need Help??

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

I have been trying to use this module to do a tail -f on a windows logfile. I had some perl code to do it that I posted before and below, but it was reading the whole file and thus using too much memory. I tried ppm to load File::Tail and it looks for File::HiRes, yet the PM goes in Time::HiRes. I have struggled for hours trying to get this PM loaded.
I am ready to pay someone to help me.
I just need an efficient way to that won't use alot of memory to 'tail -f' a large windows file. That is all.

perl somescript.pl thefile > outputfile

I have this
$firstrun = 1; while(1) { if ( -s $file ) { sleep 1; open(TF,$file) || next ; seek(TF,0,0); @lines=<TF>; my $curpos=tell(TF); close(TF); if ( $firstrun < 1 ){ foreach $lyne (@lines){ printf $lyne; } } sleep 1; $firstrun = 0; while(-s $file ) { open(TF,$file) || last ; seek(TF,$curpos,0); @lines=<TF>; $curpos = tell(TF); last if ((stat(_))[7] < $curpos); foreach $lyne (@lines){ printf $lyne; } close(TF); sleep 1; } } else { sleep 5; } }

but it is a memory hog. Plus, sometimes I am not allowed to install PMs like File::Tail.
I like this offered by another Monk, but I am not skilled enough (see above) to turn it into efficient code.
while (1) { stat the file if size of file changed since last time { open file seek to previous EOF print file contents until EOF save EOF position for next time close the file } sleep for x seconds }
Can anyone help with making the above not read through the whole file, possibly becoming more memory efficient ?
Thanks

Replies are listed 'Best First'.
Re: File::Tail on win32
by GrandFather (Saint) on Nov 29, 2005 at 23:20 UTC

    THe following sample code should do it for you. You should omit the updateFile related code - that's just there to get the test file updated.

    use strict; use warnings; my $logFileName = 'test.txt'; my $lastPos = 0; my $endTime = time + 60; while (time < $endTime) { next if ! -e $logFileName; next if $lastPos >= -s $logFileName; open inFile, '<', $logFileName; seek inFile, $lastPos, 0; print while <inFile>; $lastPos = tell inFile; close inFile; } continue { sleep (5); updateFile (); } sub updateFile { open outFile, '>>', $logFileName; print outFile 'Line added to file at ' . (join ', ', localtime) . "\n" +; close outFile; }

    Printed:

    Line added to file at 30, 16, 12, 30, 10, 105, 3, 333, 1 Line added to file at 35, 16, 12, 30, 10, 105, 3, 333, 1 Line added to file at 40, 16, 12, 30, 10, 105, 3, 333, 1 Line added to file at 45, 16, 12, 30, 10, 105, 3, 333, 1 Line added to file at 50, 16, 12, 30, 10, 105, 3, 333, 1 Line added to file at 55, 16, 12, 30, 10, 105, 3, 333, 1 Line added to file at 0, 17, 12, 30, 10, 105, 3, 333, 1 Line added to file at 5, 17, 12, 30, 10, 105, 3, 333, 1 Line added to file at 10, 17, 12, 30, 10, 105, 3, 333, 1 Line added to file at 15, 17, 12, 30, 10, 105, 3, 333, 1 Line added to file at 20, 17, 12, 30, 10, 105, 3, 333, 1

    DWIM is Perl's answer to Gödel
      thanks, I'll hook it up to large file and try it.
      The script behaves strangely when the source file is removed and recreated.
      like so, test.txt is created by doing echo "" > test.txt
      run -> perl this.pl
      other window (ow) echo one >> test.txt
      one
      (ow) echo two >> test.txt
      two
      (ow) del /F test.txt
      (ow) echo uno > test.txt
      (ow) echo due >> test.txt
      (ow) echo tre >> test.txt
      re
      (ow) echo quattro >> test.txt
      quattro

      So it seems to hold on to the last cursor position and won't yield any output until that last postion is surpassed ?
      Also when you first run it, it outputs the entire file, is it possible to set $lastpos to its current EOF line ? ie Can it go to the bottom and wait for the next newline ?
      Also if I wanted to hand the output to a program, rather than print, how would I change
      print while <inFile>; ??
      Thanks !

        This modified version may be closer to what you want:

        use strict; use warnings; my $logFileName = 'test.txt'; my $highWater = -1; # Signal first time through while (1) { next if ! -e $logFileName; if ($highWater >= -s $logFileName) { $highWater = -s $logFileName; # Reset high water mark next; } open inFile, '<', $logFileName; seek inFile, $highWater, 0; #my @lines; # Uncomment to collate lines while (<inFile>) { print $_; # Replace with alternate code to handle output. #push @lines, $_; #Uncomment to collate lines } $highWater = tell inFile; close inFile; # Use @lines as required here to deal with added lines in one hit. e +g.: #print @lines; #Uncomment to print collated lines } continue { sleep (5); }

        DWIM is Perl's answer to Gödel

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others exploiting the Monastery: (4)
As of 2024-04-19 23:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found