Skip to content

Latest commit

 

History

History
125 lines (89 loc) · 4.91 KB

perlnewopentut.pod

File metadata and controls

125 lines (89 loc) · 4.91 KB

NAME

perlopentut - tutorial on opening files and such in Perl

DESCRIPTION

Perl has two ways to open things: the shell-style open for convenience, and C-style sysopen for precision.

Shell-style open

Perl's open function is detailed in perldoc -f open; this tutorial presents hints, tips, and best practices in an onramp-style tutorial that makes it easy to get started.

Simple opens

To open and read from a file, you create a filehandle with the open function, then read from the filehandle:

open my $filehandle, '<', 'file_to_read.txt';
while (<$filehandle>) {
    # do whatever you want with $_, which is a single line
    # from the file
}
close $filehandle;

Filehandles created in this way are lexically-scoped scalars, just like any other reference declared with my. There are several special global filehandles as well:

STDIN - standard input
STDOUT - standard output
STDERR - standard error
DATA - reads from a special __DATA__ section at the end of a Perl source file.

You can also create this kind of global filehandle if you want, but lexically- scoped filehandles are usually suitable.

The open function takes three arguments: a scalar to store a reference to the filehandle, a string representing the open mode (and, optionally, the encoding), and another string specifying the filename to open:

open my $fh, '<', '/etc/motd';

This kind of lexical filehandle can be passed between subroutines like any other scalar, and is implicitly closed when it falls out of scope (more on that later).

Common open modes are:

<       read
>       write (truncates an existing file if open succeeds, or creates a new file)
>>      append (adds to the end of an existing file, or creates a new file for writing)
+<      read-write (without truncating the file)
+>      read-write (truncate existing file)
|-      a pipe to an external program (filename is the command)
-|      a pipe from an external program (filename is the command)

As always, practice defensive programming by ensuring that error conditions are handled appropriately. File permissions might block a file from being opened, the file might not exist, or there might be a filesystem error - all these need to be handled appropriately. open returns true on success, and a false value on failure. As well, failure will cause the predefined variable $! to be set with the system error.

open my $fh, '<', '/etc/motd' or die "Couldn't open /etc/motd for reading: $!";

However, doing this for every open and close of a filehandle is repetitive, and therefore error-prone, thereby violating the DRY (Don't Repeat Yourself) principle. Instead, you can use the autodie pragma to have Perl automatically throw sensible exceptions (probably better than what you'd write yourself) when an open fails. The autodie pragma was included with Perl as of 5.10.1, but can be installed on older Perls.

use autodie;
open my $in, '<', '/etc/motd'; # throws an exception on failure

If a filehandle was opened previously, it is implicitly closed prior to the new open being attempted. Lexical filehandles are also implicitly closed when they fall out of scope. This can hide errors under some circumstances. For example, an explicit close will fail if the filehandle was already closed. Implicitly closing a filehandle can be problematic when you need to check whether the close encountered a failure condition, for example, if you opened a pipe to another program.

close will return false and put error details in $! just like a failed open call. Likewise, autodie will make close throw an exception.

Specifying file encodings

When dealing with input & output, you must decode incoming data as the first thing, and encode outgoing data as the last thing. Perl can often do this automatically if you set encoding layers on your filehandles. You can set layers on a filehandle after the fact, using the binmode function, or set default layers with the open pragma, but the most common way is to specify encoding layers in the second parameter of the open call, alongside the open mode.

use autodie; # to avoid repetitive error-handling code
binmode STDIN, ':encoding(cp1252)';
open my $out, '> :raw :encoding(UTF-16LE) :crlf', $filename;
print $out while <STDIN>;
close $out;
close STDIN;

See PerlIO for the :utf8 layer, PerlIO::encoding for the :encoding() layer, and Encode::Supported for many encodings supported by the Encode module.

For UTF-8, you almost certainly want to use the layer :encoding('UTF-8') for safety and correctness. See perluniintro for information on Unicode/UTF-8.

Writing to an in-memory file

You can read from and write to an in-memory "file" that is actually a scalar by passing a reference to the scalar as the filename in an open call:

open my $fh, '>', \$str;