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

Is it legal to put the contents of a file into a scalar? And if so, how can you open a file and then put it into a scalar value? I thought join could do it:
open ($FILE, $txt_file) || die "Cannot open $txt_file:$!"; $contents=join('',<FILE>);
But this doesnt work. Any ideas? Thanks!

Replies are listed 'Best First'.
Re: Putting file contents into a scalar
by joe++ (Friar) on Oct 29, 2002 at 12:35 UTC
    You're nearly there, but should specify the file-handle as a 'bareword', like FILE instead of $FILE.

    This will do the trick:

    my $contents; { local $/; open (FILE, $txt_file) || die "Cannot open $txt_file:$!"; $contents = <FILE> }
    Update: You would likely have been warned if you used strict (because $FILE was uninitialised).
    As a sidenote: there is a nice idiom to slurp in a file in thread Cheap idioms.

    --
    Cheers, Joe

      You can specify a filehandle as:

      my $fh;

      The root nodes problem is that he/she tried FILE and then $FILE, which does not work.

      *FILE != $FILE

      I prefer to use the $ convention, as opposed to the bareword. I think it keeps my code cleaner, as I don't feel the need to double-check for any other "barewords" that might not be what I was expecting.

      Just my two cents...

      John J Reiser
      newrisedesigns.com

        For my own code, I even prefer to use IO::File because that gives me all that neat OO stuff on the file handle. And the additional benefit to be able to test for the type of a scalar which happens to be passed to me, by checking for ref $fh eq 'IO::File'.

        But that's much typing for oneliners...

        Update: As merlyn correctly pointed out:

        "Please don't do that. Your code is fragile. It will break when I pass an object that subclasses IO::File but acts in every way like an IO::File".
        So I went through my latest and greatest module, which grossly offends against this statement, and quietly changed my test to read:
        ... croak("Invalid type for 'outfile', missing method print()'") unless $outfile->can('print'); ...
        The immediate benefit is that I now can use IO::Scalar from my test script to get output in a variable instead of a file (or STDOUT). Cool!

        --
        Cheers, Joe

Re: Putting file contents into a scalar
by vek (Prior) on Oct 29, 2002 at 13:37 UTC
    Yes it's perfectly legal. Like Foxcub I would slurp the contents like this:
    my $fileContents; open (FILE, $txt_file) || die "Could not open $txt_file - $!\n"; while (<FILE>) { $fileContents .= $_; } close (FILE);
    NOTE: Make sure that slurping the file into a scalar is really what you want to do. Obviously there's no problem if the file is small(ish). You might run into memory issues if you try slurping large files into memory. Perhaps you could give us some indication on what you plan on doing with the scalar. We could offer some advice as to whether that's the best way to go...

    -- vek --
Re: Putting file contents into a scalar
by Aristotle (Chancellor) on Oct 29, 2002 at 20:14 UTC
    Using a while loop as Foxcub and vek advertise will do the trick, but joe++'s version is better. With the loops, you pay for the cost of reading the file line by line, only to just join all the lines back together. You should either localize $/ to slurp the file or say something like:
    open my $fh, "<", $txt_file or die "Cannot open $txt_file: $!"; read $fh, my $contents, -s $fh;
    Also, please don't ever just say open(FH, $variable). If your $variable comes from user input, people can do malicious tricks like starting the "filename" with a > or end it with a | to make your script clobber files or execute commands when it runs. By using the three-argument form of open you avoid security holes or just plain bugs.

    Makeshifts last the longest.

Re: Putting file contents into a scalar
by Tanalis (Curate) on Oct 29, 2002 at 12:38 UTC
    Yeah, it's legal. I think.

    The way I'd do it, if I had to, would be something like:

    my $contents; while (<FILE>) { $contents .= $_; }

    Note that I haven't tested that, though .. but I can't see why it shouldn't work.

    Hope that helps ..
    --Foxcub