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

A module I'm using expects me to pass it a file handle it then prints to. I want to redirect the printed content to a scalar instead of a file on disk.

Perl 5.8. has open($fh, '>', \$dest), but I am looking for something that will ideally work back to 5.005something, on Unix and Windows, without requiring non-core modules. Is there a way to do it?

Replies are listed 'Best First'.
Re: Portable in-memory files
by nothingmuch (Priest) on Apr 06, 2003 at 20:54 UTC
    You can hack up a tied filehandle, which is actually a scalar (there are prolly a gazillion out there):
    package Scandle; sub TIEHANDLE { my ($buffer, $pos); bless [ $buffer, $pos],shift }; sub WRITE { my $self = shift; $self->PRINT($#_ ? substr($_[0],0,$_[1]) + : $_[0] ); } sub PRINT { my $self = shift; my $write = shift; if ($self->[1] != length($self->[0]){ if (length($write) > length($self->[0])-$self->[1]){ substr($self->[0],$self->[1],length($_[0])-$self->[1],''); } else { substr($self->[0],$self->[1],length($write),$write); $self->[1] += length($write); return 1; } } $self->[0] .= $write; $self->[1] = length($self->[0]) }
    this should take care of most of it... emulate whatever more you need. untested.

    -nuffin
    zz zZ Z Z #!perl

      Thanks very much! I added

      sub CLOSE { my $self = shift; return $self->[0]; }
      so I can get at the content nicely by close()ing the handle.

Re: Portable in-memory files
by jmcnamara (Monsignor) on Apr 06, 2003 at 21:17 UTC

    The IO::Scalar module can be used create a filehandle that acts as a scalar. It is fully portable.

    It is a non-core module, which doesn't meet your last requirement but there are other ways around that.

    --
    John.

Re: Portable in-memory files
by BrowserUk (Patriarch) on Apr 06, 2003 at 23:44 UTC

    I wonder if the c-library in question would accept/work with a handle to a pipe? I guess it depends on whether it just writes to the file descriptor, or whether it does any seeks.

    If it will, then you could fork, give the library routine the handle to one end of the pipe in the child and read the results back in the parent.

    There is a short sample program in perlipc under the heading "Bidirectional Communication with Yourself" which would serve as a starting point.


    Examine what is said, not who speaks.
    1) When a distinguished but elderly scientist states that something is possible, he is almost certainly right. When he states that something is impossible, he is very probably wrong.
    2) The only way of discovering the limits of the possible is to venture a little way past them into the impossible
    3) Any sufficiently advanced technology is indistinguishable from magic.
    Arthur C. Clarke.
Re: Portable in-memory files
by crenz (Priest) on Apr 06, 2003 at 22:12 UTC

    Update

    I'm trying to use this with Compress::Zlib. Unfortunately, gzopen expects a real filehandle. It calls gzdopen on the file descriptor (returned by FILENO), a zlib-internal function written in C. I'm out of my wits.

    *sigh*

    In case anybody is wondering why I am doing this: I am trying to create in-memory .tar.gz files. Unfortunately, if I use memGzip to compress Archive::Tar's output, the resulting file cannot be read by some tar programs. I presume the reason is that memGzip only creates a minimal gzip file header.

      Archive::Tar has built-in support to gzip its output files for you. Just specify that compression is true. See the description for the methods "new", "read", and "write": the second argument must be true.

        Unfortunately, when looking at the source, I found out that the output is only compressed when going to a file. So that's not helpful for me.