100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

File I/O in Perl

Learn how to open, read, write, and safely close files in Perl using lexical filehandles, three-argument open, and proper error checking.

Text ProcessingIntermediate10 min readJul 10, 2026
Analogies

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.

perl
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.

perl
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

Was this page helpful?

Topics covered

#Programming#PerlStudyNotes#FileIOInPerl#File#Perl#Opening#Files#StudyNotes#SkillVeris#ExamPrep