Last Updated: December 26, 2018
· worr

Correctly opening a file in Perl

Let's start with some code, shall we?

use strict;
use warnings;
use v5.14;

# Let's just pull off the first argument and use it 
# as our filename
my $filename = $ARGV[0];

if ($filename) {
    # Discussed more in detail below
    open(my $fh, '<', $filename) or die "$!";

    # Close the file, even though it will close when the 
    # filehandle falls out of scope

Three-argument open

The first important takeaway here is using three argument open.

There exists a version of open that takes only two arguments, and the mode (<, >, |-, or -|) is concatenated with the filename.

This is bad, for obvious reasons. Let's say we had code that looked like this:

open(my $fh, $filename);

What would happen if we passed in a file that named '>myfile'? In that case, Perl would instead open that file with for writing rather than reading, as we intended.

Checking the result of open()

It's very important to check the result of open(), as files will refuse to open for all sorts of reasons (they don't exist, permissions, etc.). It's important to report this back to the user, and take the appropriate action. In my case, since this program doesn't do anything other than open a file, I die.

Lexical filehandles

Now you might have seen code that uses a glob instead of a scalar to hold a filehandle.

open(FH, '>', $filename);

This is bad, as the filehandle isn't automatically closed when FH falls out of scope. While you ought to manually close your filehandles when you're done with them, making them scalars causes them to close automatically when they fall out of scope, providing an extra safeguard.

Not only that, but they don't pollute as many namespaces as typeglobs do, however that's a subject for another time.

2 Responses
Add your response

Thanks for the feedback.

I made sure to only call open if $filename isn't a falsey value, and to explain my reasoning behind die in the protip

over 1 year ago ·

Remember people also might be using unicode characters.

open(my $fh, "<:encoding(UTF-8)", "filename") or die $!;

over 1 year ago ·