to read a line, we've been reading from the standard input file. Standard input is the input provided by a user either directly as we've seen, by typing on the keyboard, or indirectly, through the use of a 'pipe' that (as we'll see) pumps input into the program.
As a counterpart to standard input, there's also standard output: STDOUT. Conversely, it's the output we provide to a user, which at the moment we're doing by writing to the screen. Every time we've used the function print so far, we've been implicitly using STDOUT:
print STDOUT "Hello, world.\n";
is just the same as our original example in Chapter 1. There's one more 'standard' filehandle: standard error, or STDERR, which is where we write the error messages when we die.
Every program has these three filehandles available, at least at the beginning of the program. To read and write from other files, though, you'll want to open a filehandle of your own. Filehandles are usually one-way: You can't write to the user's keyboard, for instance, or read from his or her screen. Instead, filehandles are open either for reading or for writing, for input or for output. So, here's how you'd open a filehandle for reading:
open FH, $filename or die $!;
The operator for opening a filehandle is open, and it takes two arguments, the first being the name of the filehandle we want to open. Filehandles are slightly different from ordinary variables, and they do not need to be declared with my, even if you're using strict as you should. It's traditional to use all-capitals for a filehandle to distinguish them from keywords.
The second argument is the file's name - either as a variable, as shown above, or as a string literal, like this:
open FH, 'output.log' or die $!;
You may specify a full path to a file, but don't forget that if you're on Windows, a backslash in a double-quoted string introduces an escape character. So, for instance, you should say this:
open FH, 'c:/test/news.txt' or die $!;
rather than:
open FH, "c:\test\news.txt" or die $!;
as \t in a double-quoted string is a tab, and \n is a new line. You could also say "c:\\test\\news.txt" but that's a little unwieldy. My advice is to make use of the fact that Windows allows forward slashes internally, and forward slashes do not need to be escaped: "c:/test/news.txt" should work perfectly fine.
So now we have our filehandle open - or have we? As I mentioned in Chapter 4, the X or Y style of conditional is often used for ensuring that operations were successful. Here is the first real example of this.
When you're dealing with something like the file system, it's dangerous to blindly assume that everything you are going to do will succeed. A file may not be present when you expect it to be, a file name you are given may turn out to be a directory, something else may be using the file at the time, and so on. For this reason, you need to check that the open did actually succeed. If it didn't, we die, and our message is whatever is held in $!.
What's $!? This is one of Perl's special variables, designed to give you a way of getting at various things that Perl wants to tell you. In this case, Perl is passing on an error message from the system, and this error message should tell you why the open failed: It's usually something like 'No such file or directory' or 'permission denied'.
There are special variables to tell you what version of Perl you are running, what user you are logged in as on a multi-user system, and so on. Appendix B contains a complete description of Perl's special variables.
So, for instance, if we try and open a file that is actually a directory, this happens:
#!/usr/bin/perl
# badopen.plx
use warnings;
use strict;
open BAD, "/temp" or die "We have a problem: $!";
>perl badopen.plx
Name "main::BAD" used only once: possible typo at badopen.plx line 5
We have a problem: Permission denied at badopen.plx line 5.
>
The first line we see is a warning. If we were to finish the program, adding further operations on BAD (or get rid of use warnings), it wouldn't show up.
You should also note that if the argument you give to die does not end with a new line, Perl automatically adds the name of the program and the location that had the problem. If you want to avoid this, always remember to put new lines on the end of everything you die with.