Приглашаем посетить
Писемский (pisemskiy.lit-info.ru)

Section 10.4.  Opening Cleanly

Previous
Table of Contents
Next

10.4. Opening Cleanly

Use either the IO::File module or the three-argument form of open.

You may have noticed that all of the examples so far use the three-argument form of open. This variant was introduced in Perl 5.6 and is more robust that the older two-argument version, which is susceptible to very rare, but subtle, failures:

    
    # Log system uses a weird but distinctive naming scheme...
    Readonly my $ACTIVE_LOG => '>temp.log<';
    Readonly my $STATIC_LOG => '>perm.log<';

    # and later...

    open my $active,  "$ACTIVE_LOG"  or croak "Can't open '$$ACTIVE_LOG': $OS_ERROR";
    open my $static, ">$STATIC_LOG"  or croak "Can't open '$STATIC_LOG': $OS_ERROR";

This code executes successfully, but it doesn't do what it appears to. The $active filehandle is opened for output to a file named temp.log<, not for input from a file named >temp.log<. And the $static filehandle is opened for appending to a file named perm.log<, rather than overwriting a file named >perm.log<. That's because the two open statements are equivalent to:

    open my $active, '>temp.log<'   or croak "Can't open '>temp.log<': $OS_ERROR";
    open my $static, '>>perm.log<'  or croak "Can't open '>perm.log<': $OS_ERROR";

and the '>' and '>>' prefixes on the second arguments tell open to open the files whose names appear after the prefixes in the corresponding output modes.

Using a three-argument open instead ensures that the specified opening mode can never be subverted by bizarre filenames, since the second argument now specifies only the opening mode, and the filename is supplied separately and doesn't have to be decoded at all:


    

    # Log system uses a weird but distinctive naming scheme...
Readonly my $ACTIVE_LOG => '>temp.log<'; Readonly my $STATIC_LOG => '>perm.log<';
# and later...
open my $active, '<', $ACTIVE_LOG or croak "Can't open '$ACTIVE_LOG': $OS_ERROR"; open my $static, '>', $STATIC_LOG or croak "Can't open '$STATIC_LOG': $OS_ERROR";

And, as a small side-benefit, each open becomes visually more explicit about the intended mode of the resulting filehandle, which improves the readability of the resulting code slightly.

The only time you should use the two-argument form of open is if you need to open a stream to or from the standard I/O streams:


    open my $stdin,  '<-' or croak "Can't open stdin: $OS_ERROR";
    open my $stdout, '>-' or croak "Can't open stdout: $OS_ERROR";

The three-argument forms:

    open my $stdin,  '<', '-' or croak "Can't open '-': $OS_ERROR";
    open my $stdout, '>', '-' or croak "Can't open '-': $OS_ERROR";

don't have the same special magic; they simply attempt to open a file named "-" for reading or writing.

As an alternative to using open at all, you can also use Perl's object-oriented I/O interface to open files via the standard IO::File module. For example, the earlier log system example could also be written:


    

    # Log system uses a weird but distinctive naming scheme...
Readonly my $ACTIVE_LOG => '>temp.log<'; Readonly my $STATIC_LOG => '>perm.log<';
# and later...
use IO::File; my $active = IO::File->new($ACTIVE_LOG, '<') or croak "Can't open '$ACTIVE_LOG': $OS_ERROR"; my $static = IO::File->new($STATIC_LOG, '>') or croak "Can't open '$STATIC_LOG': $OS_ERROR";

The resulting filehandles in $active and $static can still be used like any other filehandle. In fact, the only significant difference between using IO::File->new( ) and using open is that the OO version blesses the resulting filehandle into the IO::File class, whereas open produces raw filehandles that act like objects of the IO::Handle class (even though they're not actually blessed).

    Previous
    Table of Contents
    Next