41

I have a data file, with each line having one number, like

10
20
30
40

How do I read this file and store the data into an array?

So that I can conduct some operations on this array.

1
  • It depends on the size of the file! The solutions above tend to use convenient shorthands to copy the entire file into memory, which will work in many cases. For very large files you may need to use a streaming design where read the file by line or in chucks, process the chunks, then discard them from memory. See the answer on reading line by line with perl if that's what you need. Commented Apr 17, 2019 at 14:01

5 Answers 5

94

Just reading the file into an array, one line per element, is trivial:

open my $handle, '<', $path_to_file;
chomp(my @lines = <$handle>);
close $handle;

Now the lines of the file are in the array @lines.

If you want to make sure there is error handling for open and close, do something like this (in the snipped below, we open the file in UTF-8 mode, too):

my $handle;
unless (open $handle, "<:encoding(utf8)", $path_to_file) {
   print STDERR "Could not open file '$path_to_file': $!\n";
   # we return 'undefined', we could also 'die' or 'croak'
   return undef
}
chomp(my @lines = <$handle>);
unless (close $handle) {
   # what does it mean if close yields an error and you are just reading?
   print STDERR "Don't care error while closing '$path_to_file': $!\n";
} 
1
  • 4
    You should really handle the case for the 'open' failing, either by checking the return value or using autodie. To be properly correct you should also do the same for the 'close'.
    – zgpmax
    Commented Jan 23, 2012 at 12:06
15

There is the easiest method, using File::Slurp module:

use File::Slurp;
my @lines = read_file("filename", chomp => 1); # will chomp() each line

If you need some validation for each line you can use grep in front of read_file.

For example, filter lines which contain only integers:

my @lines = grep { /^\d+$/ } read_file("filename", chomp => 1);
3
  • 1
    Not really. You forgot chomp. Perhaps this would work better: my @data = map {chomp $_; $_} read_file("filename"); Commented Jan 22, 2012 at 22:35
  • At first I hadn't paid attention, each line of a file contains one number. So, it will be better to put regex for numbers into map instead of chomp. Updated.
    – Taras
    Commented Jan 22, 2012 at 23:51
  • 2
    First. If someone really needs chomp() then use the option read_file("filename", chomp => 1) instead of map. Second. I don't think someone really needs a validation. The Question is not how to read numbers from a file. Third. You don't check for numbers like 3.1415. Forth. You probably want to use grep { /^\d+/ } instead of map.
    – David Raab
    Commented Jan 24, 2012 at 18:15
12

I like...

@data = `cat /var/tmp/somefile`;

It's not as glamorous as others, but, it works all the same. And...

$todays_data = '/var/tmp/somefile' ;
open INFILE, "$todays_data" ; 
@data = <INFILE> ; 
close INFILE ;

Cheers.

3
  • 1
    I would suggest adding chomp: @data = grep { chomp; } `cat /var/tmp/somefile`;
    – brablc
    Commented Sep 23, 2015 at 7:52
  • 2
    This is not a very good or secure way to do it. See perl-begin.org/tutorials/bad-elements/#slurp
    – kingsfoil
    Commented Apr 15, 2016 at 18:35
  • It's not particularly secure but if you don't care it's nice. I usually add 'and not $? or die' for an on-the-spot diagnostic in case it fails'. Commented Nov 25, 2018 at 23:06
2

Tie::File is what you need:

Synopsis

# This file documents Tie::File version 0.98
use Tie::File;

tie @array, 'Tie::File', 'filename' or die ...;

$array[13] = 'blah';     # line 13 of the file is now 'blah'
print $array[42];        # display line 42 of the file

$n_recs = @array;        # how many records are in the file?
$#array -= 2;            # chop two records off the end


for (@array) {
  s/PERL/Perl/g;         # Replace PERL with Perl everywhere in the file
}

# These are just like regular push, pop, unshift, shift, and splice
# Except that they modify the file in the way you would expect

push @array, new recs...;
my $r1 = pop @array;
unshift @array, new recs...;
my $r2 = shift @array;
@old_recs = splice @array, 3, 7, new recs...;

untie @array;            # all finished
2
  • 9
    IMHO Tie::File is an overkill for a simple task as to read a file and put the content in an array.
    – dgw
    Commented Jan 22, 2012 at 19:31
  • 1
    Tie::File is overkill unless your file is very large. Commented Jan 24, 2012 at 0:57
0

Reading from a file handle using the "diamond operator" (<>) in an array context reads all the remaining unread lines:

open(my $AAAA, '<', '/filepath/filename.txt');
my @array = <$AAAA>; # read all lines of the file into an array
close $AAAA;
2
  • 1
    Please add some verbiage to explain your answer. Commented Feb 28, 2019 at 14:38
  • Why does this answer exist? It offers no improvement over the prior answer from Sean and David Tonhofer. It is plagiarism, except that your answer is less clear. The Tonhofer edit is from January 2019, you answered in February 2019.
    – IAM_AL_X
    Commented Sep 28, 2022 at 19:19

Not the answer you're looking for? Browse other questions tagged or ask your own question.