Learning Perl Objects, References amp;amp; Modules [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Learning Perl Objects, References amp;amp; Modules [Electronic resources] - نسخه متنی

Randal L. Schwartz

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید














11.7 References to Filehandles


So far, you've seen
references to scalars, arrays, hashes, and subroutines. Another
important value type in Perl is the filehandle.

However, a filehandle
isn't stored in a variable. The filehandle is the
handle itself. You can't take a reference directly
to a filehandle.[3] However, using the
IO::File built-in class, you can create objects
that act like filehandles within Perl. Here's a
typical use:

[3] You can use the glob, take a
reference to the glob, or take a reference to the I/O structure
within a glob, but that's still not a reference to
the filehandle.


use IO::File;
my $fh = IO::File->open("/etc/passwd")
or die "constructor failed: $!";
while (<$fh>) { # $fh acts like any filehandle
print "a password line is $_";
}
close $fh; # nearly all built-ins can use IO::File

Here, $fh is constructed using the
open class method of IO::File,
and then used in places where ordinarily you'd use a
traditional (bareword) filehandle. Furthermore, you also get some
additional methods:

if ($fh->opened) { ... } # file is open
$fh->blocking(0); # make I/O be "non-blocking" if supported

The core built-in operations that use
filehandles can all use an IO::File objects
instead. If the IO::File object is within a simple
scalar variable, you can always replace the filehandle with the
scalar:

use IO::File;
my $fh = IO::File->new; # create unopened "filehandle" object
open $fh, ">my_new_file" or die "Cannot create: $!";
print $fh "$_\n" for 1..10;
close $fh;

An IO::File
object automatically gets closed cleanly when destroyed, so you can
simplify the previous code as:

use IO::File;
{
my $fh = IO::File->open(">my_new_file")
or die "Cannot create my_new_file: $!";
print $fh, "$_\n" for 1..10;
}

As $fh goes out of scope, the filehandle is
automatically closed. Nice.

If the IO::File object
is not named by a simple scalar variable, some operations require a
slightly modified syntax to work. For example, copy every file
matched by the glob pattern of *.input to a
corresponding file whose suffix is .output, but do
it in parallel. First, open all the files, both inputs and outputs:

my @handlepairs;
foreach my $file (<*.input>) {
(my $out = $file) =~ s/\.input$/.output/;
push @handlepairs, [
(IO::File->new("<$file") || die),
(IO::File->new(">$out") || die),
];
}

Now you have an array of
references to arrays, each element of which is an
IO::File object. Let's pump the
data:

while (@handlepairs) {
@handlepairs = grep {
if (defined(my $line = $_->[0]->getline)) {
print { $_->[1] } $line;
} else {
0;
}
} @handlepairs;
}

As long as you have pairs, keep passing
the list through the grep structure:

@handlepairs = grep { CONDITION } @handlepairs;

On each pass, only the handle pairs that
evaluate as true in the grep
CONDITION survive. Inside, you take the first
element of each pair and try to read from it. If
that's successful, write that line to the second
element of the pair (the corresponding output handle). If the
print is successful, it returns true, which lets
grep know that you want to keep that pair. If
either the print fails or the
getline returned undef, the
grep sees the false value as an indication to
discard that pair. Discarding the pair automatically closes both
filehandles. Cool!

Note that you can't use the more traditional
filehandle read or filehandle print operations because the reading
and writing filehandles weren't in a simple scalar
variable. Rewrite that loop to see if copying the handles is easier:

while (@handlepairs) {
@handlepairs = grep {
my ($IN, $OUT) = @$_;
if (defined(my $line = <$IN>)) {
print $OUT $line;
} else {
0;
}
} @handlepairs;
}

This scenario is arguably better. Most of the time, simply copying
the complexly referenced value into a simple scalar is easier on the
eyes. In fact, another way to write that loop is to get rid of the
ugly if structure:

while (@handlepairs) {
@handlepairs = grep {
my ($IN, $OUT) = @$_;
my $line;
defined($line = <IN>) and print $OUT $line;
} @handlepairs;
}

As long as someone understands that and is a
partial evaluator and that print returns true when
everything is OK, this is a fine replacement. Remember the Perl
motto: "There's more than one way
to do it" (although not all of them are equally nice
or legitimate).


/ 199