Book HomeLearning Perl, 3rd EditionSearch this book

11.2. Opening a Filehandle

So we see that Perl provides three filehandles -- STDIN, STDOUT, and STDERR -- which are automatically open to files or devices established by the program's parent process (probably the shell). When you need other filehandles, use the open operator to tell Perl to ask the operating system to open the connection between your program and the outside world. Here are some examples:

open CONFIG, "dino";
open CONFIG, "<dino";
open BEDROCK, ">fred";
open LOG, ">>logfile";

The first one opens a filehandle called CONFIG to a file called dino. That is, the (existing) file dino will be opened and whatever it holds will come into our program through the filehandle named CONFIG. This is similar to the way that data from a file could come in through STDIN if the command line had a shell redirection like <dino. In fact, the second example uses exactly that sequence. The second does the same as the first, but the less-than sign explicitly says "this filename is to be used for input," even though that's the default.[248]

[248]This may be important for security reasons. As we'll see in a moment (and in further detail in Chapter 14, "Process Management"), there are a number of magical characters that may be used in filenames. If $name holds a user-chosen filename, simply opening $name will allow any of these magical characters to come into play. This could be a convenience tn the user, or it could be a security hole. But opening "<$name" is much safer, since it explicitly says to open the given name for input. Still, this doesn't prevent all possible mischief. For more information on different ways of opening files, especially when security may be a concern, see the perlopentut manpage.

Although you don't have to use the less-than sign to open a file for input, we include that because, as you can see in the third example, a greater-than sign means to create a new file for output. This opens the filehandle BEDROCK for output to the new file fred. Just as when the greater-then sign is used in shell redirection, we're sending the output to a new file called fred. If there's already a file of that name, we're asking to wipe it out and replace it with this new one.

The fourth example shows how two greater-than signs may be used (again, as the shell does) to open a file for appending. That is, if the file already exists, we will add new data at the end. If it doesn't exist, it will be created in much the same way as if we had used just one greater-than sign. This is handy for log files; your program could write a few lines to the end of a log file each time it's run. So that's why the fourth example names the filehandle LOG and the file logfile.

You can use any scalar expression in place of the filename specifier, although typically you'll want to be explicit about the direction specification:

my $selected_output = "my_output";
open LOG, "> $selected_output";

Note the space after the greater-than. Perl ignores this,[249] but it keeps unexpected things from happening if $selected_output were ">passwd" for example (which would make an append instead of a write).

[249]Yes, this means that if your filename were to have leading whitespace, that would also be ignored by Perl. See perlfunc and perlopentut if you're worried about this.

We'll see how to use these filehandles later in this chapter.

11.2.1. Closing a Filehandle

When you are finished with a filehandle, you may close it with the close operator like this:

close BEDROCK;

Closing a filehandle tells Perl to inform the operating system that we're all done with the given data stream, so any last output data should be written to disk in case someone is waiting for it.[250]

[250]If you know much about I/O systems, you'll know there's more to the story. Generally, though, when a filehandle is closed, here's what happens. If there's input remaining in a file, it's ignored. If there's input remaining in a pipeline, the writing program may get a signal that the pipeline is closed. If there's output going to a file or pipeline, the buffer is flushed (that is, pending output is sent on its way). If the filehandle had a lock, the lock is released. See your system's I/O documentation for further details.

Perl will automatically close a filehandle if you reopen it (that is, if you reuse the filehandle name in a new open) or if you exit the program.[251] Because of this, many simple Perl programs don't bother with close. But it's there if you want to be tidy, with one close for every open. In general, it's best to close each filehandle soon after you're done with it, though the end of the program often arrives soon enough.[252]

[251]Any exit from the program will close all filehandles, but if Perl itself breaks, pending output buffers won't get flushed. That is to say, if you accidentally crash your program by dividing by zero, for example, Perl itself is still running. Perl will ensure that data you've written actually gets output in that case. But if Perl itself can't run (because you ran out of memory or caught an unexpected signal), the last few pieces of output may not be written to disk. Usually, this isn't a big issue.

[252]Closing a filehandle will flush any output buffers and release any locks on the file. Since someone else may be waiting for those things, a long-running program should generally close each filehandle as soon as possible. But many of our programs will take only one or two seconds to run to completion, so this may not matter. Closing a filehandle also releases possibly limited resources, so it's more than just being tidy.

11.2.2. Bad Filehandles

Perl can't actually open a file all by itself. Like any other programming language, Perl can merely ask the operating system to let us open a file. Of course, the operating system may refuse, because of permission settings, an incorrect filename, or other reasons.

If you try to read from a bad filehandle (that is, a filehandle that isn't properly open), you'll see an immediate end-of-file. (With the I/O methods we'll see in this chapter, end-of-file will be indicated by undef in a scalar context or an empty list in a list context.) If you try to write to a bad filehandle, the data is silently discarded.

Fortunately, these dire consequences are easy to avoid. First of all, if we ask for warnings with -w, Perl will generally be able to tell us with a warning when it sees that we're using a bad filehandle. But even before that, open always tells us if it succeeded or failed, by returning true for success or false for failure. So you could write code like this:

my $success = open LOG, ">>logfile";  # capture the return value
unless ($success) {
  # The open failed
  ...
}

Well, you could do it like that, but there's another way that we'll see in the next section.



Library Navigation Links

Copyright © 2002 O'Reilly & Associates. All rights reserved.