File Handling
Learn how to open, read, write, and close files in Perl, including reading line by line and the three-argument open form.
Introduction
Perl was built for chewing through text files, so its file-handling tools are simple, direct, and battle-tested. This lesson covers the modern, safe way to open files, read them (both line by line and all at once), write new content, and append to existing files.
- How to open files safely using the three-argument form of open.
- How to read a file line by line, the most common pattern in Perl.
- How to write and append to files.
- How and why to always close filehandles.
The Three-Argument open
open takes a filehandle (stored in a lexical scalar variable), a mode, and a filename, as three separate arguments. This modern "three-argument open" form is safer than the older two-argument form because it treats the filename as pure data, avoiding surprises if a filename happens to contain special characters.
| Mode | Meaning |
|---|---|
| < | Read (the file must already exist). |
| > | Write (creates the file, or overwrites it if it already exists). |
| >> | Append (creates the file if needed, adds to the end otherwise). |
use strict;use warnings;
my $filename = "notes.txt";
open(my $fh, '>', $filename) or die "Could not open '$filename': $!";print $fh "First line of notes.\n";close($fh);
print "File written successfully.\n";Click Run to see what this code prints.
or die "..." after open is essential. If the file cannot be opened (permissions, missing directory, disk full), the script stops immediately with a clear error message instead of silently failing later.
Reading a File Line by Line
The most idiomatic way to process a text file in Perl is to open it for reading and loop over the filehandle with while, which reads one line at a time. This keeps memory usage low even for very large files, since only one line is held in memory at once.
use strict;use warnings;
my $filename = "notes.txt";
open(my $fh, '<', $filename) or die "Could not open '$filename': $!";
my $line_number = 0;while (my $line = <$fh>) { $line_number++; chomp $line; print "Line $line_number: $line\n";}
close($fh);Click Run to see what this code prints.
chomp removes the trailing newline character from $line, if there is one. Without it, every printed line would carry an extra blank line from the original file's line ending.
Reading an Entire File at Once
Sometimes it is more convenient to slurp the whole file into a single array (one element per line) or a single scalar (the whole content as one string), especially for smaller files.
use strict;use warnings;
my $filename = "notes.txt";
open(my $fh, '<', $filename) or die "Could not open '$filename': $!";my @all_lines = <$fh>;close($fh);
print "The file has ", scalar(@all_lines), " line(s).\n";print "First line: $all_lines[0]";Click Run to see what this code prints.
Writing to a File
Opening with mode > and then using print (or printf) with the filehandle sends output to the file instead of the screen. Be aware that > always overwrites the file completely if it already exists.
use strict;use warnings;
my @lines_to_write = ("Alice,29", "Bob,34", "Carol,41");
open(my $fh, '>', 'people.csv') or die "Could not open file: $!";foreach my $line (@lines_to_write) { print $fh "$line\n";}close($fh);
print "Wrote ", scalar(@lines_to_write), " lines to people.csv\n";Click Run to see what this code prints.
Notice print $fh "$line\n"; has no comma between $fh and the string. Adding a comma there (print $fh, "$line\n";) is a very common beginner mistake and produces a different, usually wrong, result.
Appending to a File
Mode >> opens the file for writing without erasing existing content — new output is added to the end. This is the mode you want for something like a running log file.
use strict;use warnings;
open(my $fh, '>>', 'people.csv') or die "Could not open file: $!";print $fh "Dave,25\n";close($fh);
open(my $read_fh, '<', 'people.csv') or die "Could not open file: $!";my @lines = <$read_fh>;close($read_fh);
print "people.csv now has ", scalar(@lines), " line(s).\n";Click Run to see what this code prints.
Closing Filehandles
Calling close explicitly when you are done with a filehandle flushes any buffered output to disk and frees the underlying file descriptor. In modern Perl, a lexical filehandle (my $fh) is also closed automatically once it goes out of scope, but explicit close calls make your intent clear and let you check for a rare close-time error.
use strict;use warnings;
open(my $fh, '>', 'important.log') or die "Could not open file: $!";print $fh "Critical data\n";close($fh) or warn "Could not close file properly: $!";Click Run to see what this code prints.
Common Mistakes
- Forgetting or die after open, causing the script to continue silently even when the file could not be opened.
- Using > when you meant >>, accidentally erasing an existing file's contents.
- Forgetting chomp when reading lines, leaving stray newline characters in the data.
- Putting a comma between the filehandle and the text in print $fh "text";, which changes its meaning.
- Using the old, unsafe two-argument open(FH, "file.txt") style instead of the modern three-argument form with a lexical filehandle.
Best Practices
- Always use the three-argument open with a lexical filehandle: open(my $fh, '<', $filename).
- Always check the result of open with or die and include $! in the error message for a useful diagnostic.
- Prefer reading line by line with while (<$fh>) for large files to keep memory usage low.
- Always chomp lines read from a file unless you specifically need the trailing newline.
- Close filehandles explicitly (and check the result on writes) rather than relying purely on automatic cleanup.
Frequently Asked Questions
$! holds the operating system's error message from the most recent failed system call, such as "No such file or directory" — extremely useful in open(...) or die "...: $!" error messages.
Not strictly, since a lexical filehandle closes automatically when it goes out of scope, but explicit close calls make code clearer and let you catch write errors on close.
Use the -e file test operator: if (-e $filename) { ... }. Perl has many other file test operators too, like -r (readable) and -d (is a directory).
Yes, using mode +< or +>, though this is uncommon for beginners; it is usually simpler to open two separate filehandles for reading and writing.
Key Takeaways
- The three-argument open(my $fh, mode, filename) is the modern, safe way to open files.
- Modes are < (read), > (write/overwrite), and >> (append).
- while (my $line = <$fh>) { ... } is the idiomatic way to read a file line by line.
- print $fh "text"; (no comma) writes to a filehandle.
- Always check open for failure with or die "...: $!", and chomp lines you read.
Summary
File handling lets Perl scripts read configuration, process logs, and produce reports — exactly the kind of automation Perl was originally built for. Next, you will learn how scripts can receive input directly from the command line itself, via @ARGV.