Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a good way to wait until a file updated and then read from it in Perl?

Tags:

perl

I was wondering if there's a way to wait for a file to be updated, and then read from it once it's updated. So if I have file.txt, I want to wait until something new is written to it, and then read it/process it/etc. Currently I am polling using Time::HiRes::sleep(.01), but I'm wondering if there's a better way. Thanks.

like image 607
Sam Lee Avatar asked Mar 02 '10 22:03

Sam Lee


People also ask

How do I open a reading and writing file in Perl?

If you want to open a file for reading and writing, you can put a plus sign before the > or < characters. open DATA, "+>file. txt" or die "Couldn't open file file.

How do I write multiple lines in a file in Perl?

Multiline String using Single & Double QuotesUser can create a multiline string using the single(”) quotes and as well as with double quotes(“”).


2 Answers

Yes there is a better way. On windows you can use the FileSystemWatcher interface, on Linux, use inotify.

Windows

use Win32::FileSystem::Watcher;

my $watcher = Win32::FileSystem::Watcher->new( "c:\\" );

# or

my $watcher = Win32::FileSystem::Watcher->new(
    "c:\\",
    notify_filter  => FILE_NOTIFY_ALL,
    watch_sub_tree => 1,
);

$watcher->start();
print "Monitoring started.";

sleep(5);

# Get a list of changes since start().
my @entries = $watcher->get_results();

# Get a list of changes since the last get_results()
@entries = $watcher->get_results();

# ... repeat as needed ...

$watcher->stop(); # or undef $watcher

foreach my $entry (@entries) {
    print $entry->action_name . " " . $entry->file_name . "\n";
}

# Restart monitoring

# $watcher->start();
# ...
# $watcher->stop();

LINUX

use Linux::Inotify2;
my $inotify = new Linux::Inotify2();

foreach (@ARGV)
{
  $inotify->watch($_, IN_ALL_EVENTS);
}

while (1)
{
  # By default this will block until something is read
  my @events = $inotify->read();
  if (scalar(@events)==0)
  {
    print "read error: $!";
    last;
  }

  foreach (@events)
  {
    printf "File: %s; Mask: %d\n", $_->fullname, $_->mask;
  }
}
like image 163
Byron Whitlock Avatar answered Nov 14 '22 21:11

Byron Whitlock


File::Tail will poll the file, but has a few advantages over your approach:

  • The poll time is recomputed dynamically based on the number of lines written since the last poll
  • If the file remains unchanged, polling will slow to avoid using up CPU
  • File::Tail will detect if the file has been truncated, moved and/or recreated, and silently re-open the file for you
  • It can tie a regular file handle which you can use like normal without any special API or syntax.

Example from the perldoc:

use File::Tail;
my $ref=tie *FH,"File::Tail",(name=>$name);
while (<FH>) {
    print "$_";
}
like image 44
rjh Avatar answered Nov 14 '22 23:11

rjh