Working with Files and I/O in Perl

Read, write, and append files safely in modern Perl using three-argument open, lexical filehandles, and proper error handling.

  • perl
  • files
  • io
  • filehandles

File handling is everyday Perl. This is the modern, safe way to do it — three-argument open, lexical filehandles, and always checking for errors.

Reading a file line by line

open(my $fh, '<', 'notes.txt') or die "Can't open notes.txt: $!";
while (my $line = <$fh>) {
    chomp $line;
    print "read: $line\n";
}
close($fh);
  • Three-argument open keeps the mode (<) separate from the filename — safer than the old two-argument form.
  • my $fh is a lexical filehandle: it closes automatically when it goes out of scope, and you can pass it around like any variable.
  • or die "... $!" reports the reason ($! holds the OS error) instead of failing silently.

Writing and appending

open(my $out, '>', 'report.txt') or die "Can't write: $!";   # overwrite
print $out "line one\n";
close($out);

open(my $add, '>>', 'report.txt') or die "Can't append: $!"; # append
print $add "line two\n";
close($add);

Reading an entire file at once

For small files, slurping is convenient. The cleanest modern approach uses Path::Tiny from CPAN:

use Path::Tiny;
my $whole = path('notes.txt')->slurp_utf8;
my @lines = path('notes.txt')->lines_utf8;

Handling text encoding

Real-world text is usually UTF-8. Be explicit so accented and non-Latin characters survive:

open(my $fh, '<:encoding(UTF-8)', 'names.txt') or die $!;

A complete example: filter a file

Copy only the lines that contain “ERROR” into a new file:

#!/usr/bin/env perl
use strict;
use warnings;

open(my $in,  '<', 'app.log')    or die "read: $!";
open(my $out, '>', 'errors.log') or die "write: $!";
while (my $line = <$in>) {
    print $out $line if $line =~ /ERROR/;
}
close($in);
close($out);

Where to go next

Many file tasks collapse into a single command with Perl One-Liners for Text Processing.