Opening Files with Lexical Filehandles
Modern Perl opens files with the three-argument form of open: open(my $fh, '<', 'data.txt') or die "Cannot open data.txt: $!"; where the first argument is a lexical scalar that becomes the filehandle, the second is the mode ('<' read, '>' write/truncate, '>>' append), and the third is the filename. Using a lexical variable instead of a bareword filehandle like FH means the handle is automatically closed when it goes out of scope, and it avoids the global-namespace collisions that old-style bareword handles could cause in larger programs. The or die ... $! pattern is essential: $! holds the operating system's error message explaining exactly why the open failed, such as permission denied or file not found.
Cricket analogy: Just as a team assigns a specific player, not a generic 'someone', to field at deep cover for this over, open(my $fh, ...) assigns a specific lexical variable to represent this file, not a generic global name.
open(my $fh, '<', 'data.txt') or die "Cannot open data.txt: $!";
while (my $line = <$fh>) {
chomp $line;
print "Read: $line\n";
}
close($fh) or die "Cannot close data.txt: $!";
Reading Lines and the Diamond Operator
The <$fh> diamond-style read operator, when used in list context, reads every remaining line into a list, and in scalar context, as in a while loop condition, reads one line at a time including the trailing newline. The idiom while (my $line = <$fh>) is preferred over while ($line = <$fh>) because it correctly stops on a line containing only '0', which Perl would otherwise treat as false and exit the loop prematurely. chomp($line) removes exactly one trailing newline character from the end of a string, which is almost always the very next thing you do after reading a line, since most further processing, comparisons, or printing works better without a dangling \n.
Cricket analogy: Just as a scorer records one ball at a time, updating the tally after each delivery rather than the whole innings at once, while (my $line = <$fh>) processes one line at a time rather than the whole file at once.
Always prefer while (my $line = <$fh>) over while ($line = <$fh>). The my-in-condition form correctly treats a line containing only '0' as a valid read, whereas the bare assignment form evaluates to false on '0' and would silently truncate the loop.
Writing and Appending to Files
Opening with mode '>' creates a new file or truncates an existing one to zero length before writing, while '>>' opens for appending, positioning the write pointer at the current end of the file without erasing prior content. print $fh 'text' (note: no comma between the filehandle and the following expression) sends output to the filehandle instead of to STDOUT; forgetting to omit that comma is one of the most common beginner mistakes since print($fh, 'text') is silently interpreted differently. It's good practice to check both the close() call's return value and, ideally, use autodie or explicit error checks, since a failed close can indicate a write that didn't fully flush to disk.
Cricket analogy: Just as a team starts a fresh scorecard for a new match rather than continuing yesterday's tally, mode '>' starts a fresh file, truncating old content, while '>>' continues adding to the existing scorecard like a running series total.
open(my $out, '>>', 'log.txt') or die "Cannot open log.txt: $!";
print $out "Job finished at " . localtime() . "\n";
close($out) or die "Cannot close log.txt: $!";
Do not write print ($fh, "text\n"); with a comma or parentheses wrapped that way — Perl parses ($fh, "text\n") as a list argument to print, which sends everything to STDOUT and silently drops the intended filehandle. The correct form is print $fh "text\n"; with no comma.
Closing Handles and Checking for Errors
Every filehandle opened should eventually be closed, either explicitly with close($fh) or implicitly when the lexical variable goes out of scope, but explicit closing with error checking, close($fh) or warn "Error closing file: $!", is important for write operations because it's the point at which buffered data is actually flushed to disk and disk-full or permission errors can surface. The autodie pragma, use autodie; at the top of a script, automatically makes built-ins like open, close, and read die with a descriptive message on failure, eliminating the need to write or die "..." after every single I/O call.
Cricket analogy: Just as an umpire only signals the innings truly complete after confirming the scorebook is correctly closed out, close($fh) is the point where Perl confirms buffered writes are truly flushed to disk.
- Use the three-argument open(my $fh, '<', $file) form with lexical filehandles, never the old two-argument or bareword style.
- Always check open's return value with 'or die "...: $!"' since $! explains exactly why the open failed.
- '<' opens for reading, '>' truncates and opens for writing, '>>' opens for appending without erasing content.
- while (my $line = <$fh>) is the safe idiom for reading line by line; always chomp the line right after.
- print $fh 'text' has no comma between the filehandle and the text; adding one breaks the write silently.
- Explicitly close() filehandles and check the return value, since that's when buffered writes actually flush to disk.
- The autodie pragma removes the need to write 'or die' after every I/O call by making failures die automatically.
Practice what you learned
1. Which line correctly opens a file for reading using modern Perl best practice?
2. What does the mode string '>>' mean when passed to open?
3. Why is while (my $line = <$fh>) preferred over while ($line = <$fh>)?
4. What is wrong with the statement print ($fh, "Hello\n");?
5. What does the autodie pragma do?
Was this page helpful?
You May Also Like
String Functions in Perl
Master Perl's built-in string toolkit — length, substr, index, uc/lc, and concatenation — for everyday text manipulation without reaching for regex.
Regular Expressions in Perl
Learn how Perl's built-in regex engine lets you match, capture, and substitute text patterns using operators like m//, s///, and tr///.
split, join, and map
Learn Perl's core list-transformation trio: split to break strings into lists, join to reassemble them, and map to transform every element.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics