PrevIndexNext
Reading and Writing Files
One of Perl's mottos is:
Making Easy Things Easy and
Hard Things Possible.
In some languages even easy things are hard.
In some languages, hard things are not possible.
Text files are ubiquitous - they are
the 'lingua franca' of the cyber world.
Configuration files, HTML, Postscript, RTF,
program source files, XML, email.
All of these are text files.
Reading and writing them should be easy.
Reading Files
With your favorite text editor create a file of names:
names.txt
-------
Art
Bob
Zoe
Christian
Sabrina
Marge
Here is a Perl program to read that file:
open NAMEIN, "names.txt";
$line = <NAMEIN>;
print "hello, $line";
close NAMEIN;
It reads the first line and prints:
hello, Art
The name "NAMEIN" is called a file handle.
The name can be any word you wish.
It is conventionally in UPPER CASE.
To read all lines:
open NAMEIN, "names.txt";
while ($line = <NAMEIN>) {
print "hello, $line";
}
close NAMEIN;
Note that we are making an assignment to $line within the boolean
of the while. This is okay. The value of an assignment
is the value that was assigned.
The loop will terminate when the end of the file is reached.
At this point $line will be assigned 'undef' which is false.
If the file "names.txt" may not exist
you need to watch for that:
if (not open NAMEIN, "names.txt") {
print "cannot open names.txt\n";
exit;
}
The function 'exit' will immediately exit the program.
Nothing else will happen.
The function 'die' prints an error message and then exits.
So equivalently we have:
if (not open NAMEIN, "names.txt") {
die "cannot open names.txt\n";
}
The usual, more concise, and fun way of writing this is:
open NAMEIN, "names.txt" or die "cannot open names.txt\n";
If you are curious WHY it could not open
the file you can do this:
die "cannot open names.txt: $!\n";
$! contains the error message from the
last system command that failed. The mnemonic
for this is "What Went Bang?". :)
$! is a rather
cryptic variable name but it is one of many
that are commonly used in Perl so you might as well
start getting used to them! Other common ones are $_, @_, $/, $|, $&.
They all have some clever mnemonic.
Writing Files
To CREATE a text file:
open OUT, ">nums.txt" or
die "cannot create nums.txt: $!\n";
for ($i = 1; $i <= 10; ++$i) {
print OUT "$i\n";
}
close OUT;
Note the ">" as the first character of the
second parameter to open. This causes the
file to be created (it is overwritten if it already exists)
and opened for writing.
Note that the same built-in function
'print' is used to print to the standard output (the terminal screen)
and to print to files. This is nice but may be confusing.
The difference is that when printing to a file
you put a filehandle directly after 'print'.
It is important that you do NOT put a COMMA (,) after
the filehandle in the print statement. See above.
There is no comma after the 'OUT'.
When opening a file for output the file will be overwritten and truncated
if it already exists. If you want to add to the end of
the file rather than starting all over again you can do this:
open OUT, ">>data.txt" or die "could not append to data.txt: $!\n";
This opens the file for appending. See the ">>" instead of ">".
A Better Way
These notes were written in 2001. There is now (2012) a better
and more robust way to read and write files. It is explained fully
in the book "Perl Best Practices". A simple example should suffice:
#
# copy a file replacing all a's with A.
#
open my $in, '<', "data.txt"
or die "cannot open data.txt: $!\n";
open my $out, '>', "newdata.txt"
or die "cannot create newdata.txt: $!\n";
while (my $line = <$in>) {
$line =~ s/a/A/g;
# Don't worry... :)
# The above is explained in a later chapter.
print {$out} $line;
}
close $in;
close $out;
Exercises
-
Using your text editor put an assortment of numbers, one per line,
in a text file. Open this file up, read the
lines and send the even numbers to one file (your choice of name)
and the odd ones to another.
Hint: You can use
the modulo operator '%' to determine if a number
is even or not.
$x % 2
gives the remainder when $x is divided by 2. This will
be 0 for even numbers and 1 for odd numbers.
-
Ask the user for a filename. Append the suffix ".txt"
to the filename and try to open the file for reading.
If you can't ask the user again. Keep asking until you
get a good filename. Assume the file has numbers in it
one per line.
Add up all of the numbers and print the sum into a new file
with a name the same as the input file but with the word "SUM"
on the front. For example:
nums.txt
--------
3
123
9
35
SUMnums.txt
-----------
170
The user would give the filename as "nums".
-
Open a file named "files.txt" and read the lines.
Each line of this file contains another filename.
Append ".txt" to these lines and open that name.
Read all the lines counting them.
Print a report of how many lines each file had
and a grand total at the end. If you couldn't open
a file say so. It doesn't matter what is on the lines.
Just count them.
For example:
files.txt
---------
hello
great
fun
hello.txt
---------
bonjour
guten tag
buenos dias
great.txt
---------
fabulous
wonderful
The report would look like this:
hello: 3
great: 2
fun: not found
total: 5
-
To get the current date and time you can do this:
$t = localtime;
print "$t\n";
This will print a line like:
Wed Jun 4 00:34:06 2003
Make a perl script that asks the user for their name
and age and accumulates this information in a log file.
The log file will have the current date/time (as above),
the name and the age - all separated by tabs.
With several runnings of your script the log file might look
like this:
Wed Jun 4 10:34:06 2003 Joseph 34
Wed Jun 4 10:35:10 2003 Mary 12
Wed Jun 4 10:36:01 2003 Linda 3
Modify the script to continue to ask for names and ages
until you give 'q' as a name.
PrevIndexNext