Filehandles and File Tests
-----------------------------
1. Closing a Filehandle
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.
2. Bad Filehandles
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.
3. Fatal Errors with die
1) This human-readable complaint message will be available in Perl's special variable $!.
2) There's one more thing that die will do for you: it will automatically append the Perl program name and line number to the end of the message, so you can easily identify which die in your program is responsible for the untimely exit.
3) If you don't want the line number and file revealed, make sure that the dying words have a newline on the end.
4. Changing the Default Output Filehandle
1) By default, if you don't give a filehandle to print (or to printf, as everything we say here about one applies equally well to the other), the output will go to STDOUT. But that default may be changed with the select operator.
2) Once you've selected a filehandle as the default for output, it will stay that way. But it's generally a bad idea to confuse the rest of the program, so you should generally set it back to STDOUT when you're done.
3) Also by default, the output to each filehandle is buffered. Setting the special $| variable to 1 will set the currently selected filehandle (that is, the one selected at the time that the variable is modified) to always flush the buffer after each output operation.
5. Reopening a Standard Filehandle
1) We mentioned earlier that if you were to reopen a filehandle (that is, if you were to open a filehandle FRED when you've already got an open filehandle named FRED, say), the old one would be closed for you automatically. And we said that you shouldn't reuse one of the six standard filehandle names unless you intended to get that one's special features. And we also said that the messages from die and warn, along with Perl's internally generated complaints, go automatically to STDERR. If you put those three pieces of information together, you now have an idea about how you could send error messages to a file, rather than to your program's standard error stream.
# Send errors to my private error log
open STDERR, ">>/home/barney/.error_log"
or die "Can't open error log for append: $!";
2) If one of the three system filehandles -- STDIN, STDOUT, or STDERR -- fails to be reopened, Perl kindly restores the original one.
6. File Tests
1) These tests generally tell whether the system would try to permit something, but it doesn't mean that it really would be possible. For example, -w may be true for a file on a CD-ROM, even though you can't write to it, or -x may be true on an empty file, which can't truly be executed.
2) The -s test does return true if the file is nonempty, but it's a special kind of true. It's the length of the file, measured in bytes, which evaluates as true for a nonzero number.
3) When checking the age of a file, you might even get a negative value like -1.2, which means that the file's last-access timestamp is set at about thirty hours in the future! The zero point on this timescale is the moment your program started running, so that value might mean that a long-running program was looking at a file that had just been accessed. Or a timestamp could be set (accidentally or intentionally) to a time in the future.
4) You'd think that -T and -B would always disagree, since a text file isn't a binary and vice versa, but there are two special cases where they're in complete agreement. If the file doesn't exist, both are false, since it's neither a text file nor a binary. Alternatively, if the file is empty, it's an empty text file and an empty binary file at the same time, so they're both true.
5) If you omit the filename or filehandle parameter to a file test (that is, if you have just -r or just -s, say), the default operand is the file named in $_. So, to test a list of filenames to see which ones are readable, you simply type:
foreach (@lots_of_filenames) {
print "$_ is readable\n" if -r; # same as -r $_
}