Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
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 browsing the Monastery: (2)
As of 2024-04-25 20:45 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found