Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

In memory filehandles

by polettix (Vicar)
on Jan 26, 2006 at 10:57 UTC ( [id://525690]=perlquestion: print w/replies, xml ) Need Help??

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

Esteemed Monks,

I'm having a bit of troubles with in-memory filehandles, which seem to change shape behind the scenes, as the following example code seems to demonstrate.

#!/usr/bin/perl use strict; use warnings; use IO::Handle; my $data = 'some sample data here'; open my $fh, '<', \$data or die "open(): $!"; print {*STDERR} 'ref $fh yields ', ref $fh, "\n"; print_prop('$fh->can("opened")', $fh->can('opened')); print_prop('$fh->can("seek")', $fh->can('opened')); print_prop('$fh->can("seekable")', $fh->can('opened')); print_prop('$fh is IO::Handle', $fh->isa('IO::Handle')); print_prop('$fh->can("opened")', $fh->can("opened")); print_prop('$fh->opened()', $fh->opened()); print_prop('$fh->can("seek")', $fh->can("seek")); eval {print_prop('$fh->seek(0, 0)', $fh->seek(0, 0));} or print "$@"; print_prop('$fh is tied', tied $fh); close $fh; sub print_prop { my ($msg, $flag) = @_; print {*STDERR} $msg, '? ', ($flag ? 'yes' : 'no'), "\n"; return; } __END__ ref $fh yields GLOB $fh->can("opened")? no $fh->can("seek")? no $fh->can("seekable")? no $fh is IO::Handle? no $fh->can("opened")? no $fh->opened()? yes $fh->can("seek")? no Can't locate object method "seek" via package "IO::Handle" at memhandl +e.pl line 19. $fh is tied? no
Good monk dada suggested that there is a fallback to IO::Handle somewhere, and this makes sense from what I see. Now I would like to understand:
  1. is this theory correct?
  2. is IO::Handle the only possible fallback?
  3. why the fallback class doesn't support seek() and tell()? I'm able to use seek() and tell() functions on them! (e.g. seek($fh, 0, SEEK_SET); works)
Any light is highly appreciated :)

Flavio
perl -ple'$_=reverse' <<<ti.xittelop@oivalf

Don't fool yourself.

Replies are listed 'Best First'.
Re: In memory filehandles
by ysth (Canon) on Jan 26, 2006 at 11:56 UTC
    The method-calls-on-filehandles work because perl makes any filehandle an IO::Handle (or a FileHandle if you've loaded FileHandle, but that's just a wrapper around IO::Handle now I think). But IO::Handle doesn't "handle" everything; in particular, it's not an IO::Seekable. Because it perl does this across the board for every filehandle, it can't assume that it is seekable.
      So, this basically means that there aren't any hooks to plug IO::File instead of IO::Handle where needed. As a workaround, I'm using something like this:
      sub open_memory { my ($mode, $scalar_ref) = @_; open my $fh, $mode, $scalar_ref or die "open(): $!"; my $retval = IO::File->new_from_fd($fh, $mode) or die "IO::File->new_from_fd() failed"; return $retval; } ## end sub open_memory
      This makes clear that in-memory filehandles aren't a real substitute for IO::String-s as I used to believe.

      Flavio
      perl -ple'$_=reverse' <<<ti.xittelop@oivalf

      Don't fool yourself.
        Or you could just use FileHandle;. Or you could push @IO::Handle::ISA, "IO::File". Or call $fh->IO::File::seek(...).

        Except for giving easy access to the per-filehandle punctuation variables, I think the whole "let's pretend filehandles are objects" thing is pretty silly.

Re: In memory filehandles
by crouchingpenguin (Priest) on Jan 27, 2006 at 01:45 UTC
    Use IO::Scalar for this.
    #!/usr/bin/perl use strict; use warnings; use IO::Scalar; my $data = 'some sample data here'; my $fh = IO::Scalar->new(\$data); print {*STDERR} 'ref $fh yields ', ref $fh, "\n"; print_prop('$fh->can("opened")', $fh->can('opened')); print_prop('$fh->can("seek")', $fh->can('opened')); print_prop('$fh->can("seekable")', $fh->can('opened')); print_prop('$fh is IO::Scalar', $fh->isa('IO::Scalar')); print_prop('$fh->can("opened")', $fh->can("opened")); print_prop('$fh->opened()', $fh->opened()); print_prop('$fh->can("seek")', $fh->can("seek")); eval {print_prop('$fh->seek(0, 0)', $fh->seek(0, 0));} or print "$@"; print_prop('$fh is tied', tied $fh); close $fh; sub print_prop { my ($msg, $flag) = @_; print {*STDERR} $msg, '? ', ($flag ? 'yes' : 'no'), "\n"; return; }
    which yields
    ref $fh yields IO::Scalar $fh->can("opened")? yes $fh->can("seek")? yes $fh->can("seekable")? yes $fh is IO::Scalar? yes $fh->can("opened")? yes $fh->opened()? yes $fh->can("seek")? yes $fh->seek(0, 0)? yes $fh is tied? no

    cp
    ----
    "Never be afraid to try something new. Remember, amateurs built the ark. Professionals built the Titanic."
      crouchingpenguin, thanks for the suggestion. I don't like the IO::Scalar solution very much, for the same reasons I don't like using IO::String in perl 5.8.x: in-memory filehandles should work out of the box (at least this is what I thought). I tried to code a quick solution here just to work around the problem without the need to install yet another module.

      There is also another reason why I don't like IO::Scalar very much: it does not work with Archive::Zip. This is where all really started: you can't pass an in-memory filehandle to Archive::Zip, simply because it contains a seekability test that will fail. And, sadly enough, it will explicitly fail for IO::Scalar as well.

      Flavio
      perl -ple'$_=reverse' <<<ti.xittelop@oivalf

      Don't fool yourself.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (4)
As of 2024-03-29 14:30 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found