tags:

views:

848

answers:

8

I have a small text file that I'd like to read into a scalar variable exactly as it is in the file (preserving line separators and other whitespace).

The equivalent in Python would be something like

buffer = ""

try:
    file = open("fileName", 'rU')
    try:
        buffer += file.read()
    finally:
        file.close()
except IOError:
    buffer += "The file could not be opened."

This is for simply redisplaying the contents of the file on a web page, which is why my error message is going into my file buffer.

+1  A: 

You could do something like:

$data_file="somefile.txt";
open(DAT, $data_file);
@file_data = <DAT>;
close(DAT);

That'll give you the file contents in an array, that you can use for whatever you want, for example, if you wanted each individual line, you could do something like:

foreach $LINE (@file_data)
{
    dosomethingwithline($LINE);
}

For a full usage example:

my $result;
$data_file = "somefile.txt";
my $opened = open(DAT, $data_file);
if (!$opened)
{
    $result = "Error.";
}
else
{
    @lines = <DAT>;
    foreach $LINE (@lines)
    {
        $result .= $LINE;
    }
    close(DAT);
}

Then you can use $result however you need. Note: This code is untested, but it should give you an idea.

Alex Fort
To put the result in a scalar you can do this: my $text = join( "\n", @file_data ); ## untested
gpojd
Thanks for editing to show the error handling. That was helpful to a Perl newb.
Bill the Lizard
gpojd - You should join them with "", not "\n", because we never chomp()ed them, so they already have a "\n" at the end. Basically:my $text = join("", <DAT>);should work (untested).
Chris Lutz
Actually, someone else beat me to that one. Oh well, nevermind.
Chris Lutz
+16  A: 

As an alternative to what Alex said, you can install the File::Slurp module (cpan -i File::Slurp from the command line) and use this:

use File::Slurp;
# Read data into a variable
my $buffer = read_file("fileName");
# or read data into an array
my @buffer = read_file("fileName");

Note that this dies (well... croaks, but that's just the proper way to call die from a module) on errors, so you may need to run this in an eval block to catch any errors.

R. Bemrose
I just want to add that this is probably the best solution for most Perl programmers. I should have said so in the question, but I'm working on an embedded device so I'm restricted from installing any more modules than are strictly necessary.
Bill the Lizard
+12  A: 

From the Perl Cookbook:

my $filename = 'file.txt';
open( FILE, '<', $filename ) or die 'Could not open file:  ' . $!;

undef $/;
my $whole_file = <FILE>;

I would localize the changes though:

my $whole_file = '';
{
    local $/;
    $whole_file = <FILE>;
}
gpojd
Your method is better. +1 from me :)
Alex Fort
Perl Cookbook is a little advanced for my level of Perl knowledge. Where and how would I set the file handle to my filename? How do I handle errors? what does "= q{}" do?
Bill the Lizard
Sorry, let me adjust it to show the file handle. And q{some text} is just a fancy way of doing single quotes. I will remove it for clarity.
gpojd
Thanks for patiently editing this answer to show me some more details. I really appreciate it.
Bill the Lizard
Absolutely localize the $/ variable, or you'll blow up your reading of things elsewhere.
Robert P
A point for the localization.
tunnuz
I would edit this answer to show how to use lexical variables.
Brad Gilbert
+1  A: 

There is a discussion of the various ways to read a file here.

drby
A: 

Just join all lines together into a string:

open(F, $file) or die $!;
my $content = join("", <F>); 
close F;

(It was previously suggested to use join "\n" but that will add extra newlines. Each line already has a newline at its end when it's read.)

This first splits it up into lines and then joins the lines back. Not good.
drby
It satisfies the apparent needs of the questioner. It is easy to understand. It is virtually identical to the highest rated answer so far. And it doesn't require knowledge of obscure items like $/. I don't see a problem here
Harold Bamford
$/ isn't obscure. ;-) The problem is this example isn't idiomatic or efficient Perl. The accepted answer is better.
Jon Ericson
$/ is obscure to a beginning Perl programmer. I just didn't see that this answer should be downgraded. I agree that the accepted answer is better on all counts. Possibly the best part about it is the reference to the Perl Cookbook.
Harold Bamford
+12  A: 

If I don't have Slurp or Perl6::Slurp near by then I normally go with....

open my $fh, '<', 'file.txt' or die $!;

my $whole_file = do { local $/; <$fh> };

/I3az/

draegtun
This is really the most correct answer.
jrockway
Well done. An improvement over the accepted answer.
Jon Ericson
That's my choice too. +1
Axeman
Agreed, this is much better than the currently accepted answer, and more modern/concise.
Mark Canlas
+1  A: 

I don't have enough reputation to comment, so I apologize for making this another post.

@ Harold Bamford: $/ should not be an obscure variable to a Perl programmer. A beginner may not know it, but he or she should learn it. The join method is a poor choice for the reasons stated in the article linked by hackingwords above. Here's the relevant quotation from the article:

That needlessly splits the input file into lines (join provides a list context to ) and then joins up those lines again. The original coder of this idiom obviously never read perlvar and learned how to use $/ to allow scalar slurping.

Telemachus
+1  A: 

I'd tweak draegtun's answer like this, to make it do exactly what was being asked:

my $buffer;
if ( open my $fh, '<', 'fileName' ) {
    $buffer = do { local $/; <$fh> };
    close $fh;
} else {
    $buffer = 'The file could not be opened.';
}
Anirvan