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

Hello monks, I have a really weird problem and I really don't know how to fix it. I just have a simple txt file with HTML tags and some custom variables like #var1#. I'm reading that file line by line and replacing the #var1# with actual values, like a templating system. The thing is I'm getting a: "Error reading line from file: Operation timed out" when reading the lines. It actually opens the file, got a FD and a handle but everytime i try to read it pufff if gives me that error for each line... Any comments? here is the file:
<HTML> <HEAD> <TITLE>Application auto-deployed</TITLE> </HEAD> <BODY> <h1>Application information</h1><br><br> <dl> <dt>Status</dt><dd>#deploymentStatus#</dd> <dt>Name</dt><dd>#applicationName#</dd> <dt>Tag</dt><dd>#applicationTag#</dd> <dt>Environment</dt><dd>#applicationEnvironment#</dd> <dt>Triggered by</dt><dd>#triggeredBy#</dd> <dt>Completion time</dt><dd>#timeToComplete#</dd> </dl> </BODY> </HTML>
And this is the perl code:
my $isOpen = open($handle, $templateLocation); if (!-e $templateLocation || !$isOpen) { my $exception = MidTier::Exception->new("2", "Error op +ening file for reading: $templateLocation", $self); close($handle); $exception->sendLog(); } else { $logger->debug("File $templateLocation opened"); } $logger->info("Building template: $template"); while(my $line = readline($handle)) { if (!$line || $!) { $logger->error("Error reading line from file: $!") +; } else { if ($line =~ s/#((:?\w|\d)+)#/$templateValuesHash{ +$1}/g) { $logger->debug("Replacing #$1# by $templateVal +uesHash{$1} on template"); } $compiledTemplate .= $line; } } return $compiledTemplate;
Thanks for your wisdom.

Replies are listed 'Best First'.
Re: Error reading line from file: Operation timed out
by moritz (Cardinal) on May 13, 2009 at 17:13 UTC

    First of all you should improve your error handling. Checking -e after a failed open is prone to race conditions, and there are other reasons why an open could fail. Try something along these lines:

    my $isOpen = open($handle, $templateLocation); if (!$isOpen) { my $exception = MidTier::Exception->new("2", "Error opening file `$templateLocation' for reading: $!", +$self); # no need to close never opened handles $exception->sendLog(); die; # unless $exception->sendlog() dies anyway } $logger->debug("File $templateLocation opened"); $logger->info("Building template: $template");

    Then note that if (!$line test dangerous - what if a line is a false value for perl? (ie a 0 without a newline after it).

    (Another stupid idea from me: maybe the template file just lives on a network file system, and the connection hangs, and that's why you're getting timeouts?)

Re: Error reading line from file: Operation timed out
by shmem (Chancellor) on May 13, 2009 at 21:10 UTC
    if (!$line || $!) {

    There's no guarantee that $! is unset at the moment you test it. It might be propagated from elsewhere and might not mean anything here. See perlvar:

    $!
    If used numerically, yields the current value of the C "errno" variable, or in other words, if a system or library call fails, it sets this variable. This means that the value of $! is meaningful only immediately after a failure:
    if (open(FH, $filename)) { # Here $! is meaningless. ... } else { # ONLY here is $! meaningful. ... # Already here $! might be meaningless. } # Since here we might have either success or failure, # here $! is meaningless.
    In the above meaningless stands for anything: zero, non-zero, "undef". A successful system or library call does not set the variable to zero.
    (emphasis mine)

    So you should test use $! immediately after a system call which failed i.e. didn't give the expected results, in your case, if open doesn't return a true value:

    my $isOpen = open($handle, $templateLocation) or die "foo: $!";

    Your readline might succeed, but that doesn't reset $! if it was set prior to the successful readline() call.

Re: Error reading line from file: Operation timed out
by RoyCrowder (Monk) on May 13, 2009 at 17:50 UTC
    Why not just use Text::Template? The first line of the description on CPAN is "This is a library for generating form letters, building HTML pages, or filling in templates generally." As for failing to open the file, you should probably check if the file exists before you try to open it (just restating what moritz said). Also, do you happen to have a lock on the file from the filesystem or an editor? You should also check your permissions and ownership on the file as this could affect the file opening.

    The Web is like a dominatrix. Everywhere I turn, I see little buttons ordering me to Submit. (Nytwind)
      you should probably check if the file exists before you try to open it (just restating what moritz said).

      No (and it's also not what I said).

      If you first check if the file exists, and then try to open it, the file could be created or removed just between those two operations, which gives you a wrong result.

      So the rule of common sense when dealing with the world outside is never to check and then try, but simply to try, and if it went wrong look at what went wrong (which $! tells you).

        Thanks for the answers. Ok, let me clarify a few things:

        1.- The file is local on my MAC.
        2.- No other prog,user or X has the file opened.
        3.- the line I had before was a:
        (!-e $templateLocation || !open($handle, $templateLocation)) following the OR convention... but I removed that for the $isOpen (troubleshooting) hence the bad designed code.
        4.- Thanks for the Template library... I thought I looked for one pretty hard, but It seems that I didn't...
        5.- The file is simple HTML plain text to 0 per line or no \n just a basic one.

        Still getting the error after a few modifications. Actually this is really strange... because it looks like it opens the file, but when is reading the lines is when times out...

        You shouldn't make assumptions. I never said to go ahead and open the file even if it doesn't exist. If it doesn't exist, don't try to open it unless you are wanting to create it... I may not have been completely clear but there is some common sense involved here... "Checking -e after a failed open is prone to race conditions" says exactly what I'm saying. You also made the assumption that this file was in the "outside world" when that wasn't the case as per robertobouza's latest post. If the file is locally on his machine then just hammering it to see if it works is not the answer...


        The Web is like a dominatrix. Everywhere I turn, I see little buttons ordering me to Submit. (Nytwind)