2011年10月5日 星期三

Perl File Handling: open, read, write and close files


Perl File Handling: open, read, write and close files

This article describes the facilities provided for Perl file handling.

Opening files

Opening a file in perl in straightforward:open FILE, "filename.txt" or die $!;The command above will associate the FILE filehandle with the file filename.txt. You can use the filehandle to read from the file. If the file doesn't exist - or you cannot read it for any other reason - then the script will die with the appropriate error message stored in the $! variable.
What if you wanted to modify the file instead of just reading from it? Then you'd have to specify the appropriate mode using the three-argument form of open.
open FILEHANDLE, MODE, EXPRThe available modes are the following:
modeoperandcreatetruncate
read<
write>
append>>

Each of the above modes can also be prefixed with the + character to allow for simultaneous reading and writing.
modeoperandcreatetruncate
read/write+<
read/write+>
read/append+>>

Notice, how both +< and +> open the file in read/write mode but the latter also creates the file if it doesn't exist or truncates (deletes) an existing file. So, if you wanted to open a file for writing, creating it if it doesn't exist and truncating it first if does, you'd do the following:open FILE, ">", "filename.txt" or die $!This operation might fail if for example you don't have the appropriate permissions. In this case $! will be set appropriately.
The mode and the filename in the three-argument form can be combined, so the above can also be written as:open FILE, ">filename.txt" or die $!;As you might have guessed already if you just want read access you can skip the mode just as we did in the very first example above.

Reading files

If you want to read a text file line-by-line then you can do it as such:my @lines = <FILE>;The <FILE> operator - where FILE is a previously opened filehandle - returns all the unread lines of the text file in list context or a single line in scalar context. Hence, if you had a particularly large file and you wanted to conserve memory you could process it line by line:while (<FILE>) { print $_; }The $_ variable is automatically set for you to the contents of the current line. If you wish you may name your line variable instead:while (my $line = <FILE>) { ...will set the $line variable to the contents of the current line. The newline character at the end of the line is not removed automatically. If you wish to remove it you can use the chomp command. After all lines have been read the <FILE> operator will return a false value hence causing the loop to terminate.
There may cases where you need to read a file only a few characters at a time instead of line-by-line. This may be the case for binary data. To do just that you can use the read command.open FILE, "picture.jpg" or die $!; binmode FILE; my ($buf, $data, $n); while (($n = read FILE, $data, 4) != 0) { print "$n bytes read\n"; $buf .= $data; } close(FILE); There is a lot going on here so let's take it step by step. In the first line of the above code fragment a file is opened. As you can guess from the filename it is a binary file. Binary files need to treated differently than text files on some operating systems (eg, Windows). The reason is that on these platforms a newline "character" is actually represented within text files by the two character sequence \cM\cJ (that's control-M, control-J). When reading the text file Perl will convert the \cM\cJ sequence into a single \n newline characted. The converse also holds when writing files. Clearly, when reading binary data this behavior is undesired and calling binmode on the filehandle will make sure that this conversion is avoided.
The read command takes either 3 or 4 arguments. The 3-argument form is:read FILEHANDLE, SCALAR, LENGTHwhile the 4-argument form is:read FILEHANDLE, SCALAR, LENGTH, OFFSETIn the first case LENGTH characters of data are read in the variable specified by SCALAR from FILEHANDLE. The return value of read is the number of characters actually read, 0 at the end of the file or undef in the case of an error. Returning to our example above the third line of code will read at most 4 characters of data into the $data variable. The number of characters read will be stored in $n. Successive read operations on the same filehandle will set the current file position to be just before the first unread character. Thus the code above will read the contents of the file picture.jpg and store them in $buf, printing the number of characters read at every iteration.
If OFFSET is specified then the characters read will be placed at that position within the SCALAR. Taking advantage of this we could rewrite the loop above as such:my ($data, $n, $offset); while (($n = read FILE, $data, 4, $offset) != 0) { print "$n bytes read\n"; $offset += $n; }
Even though the example above demonstrates binary reading the read command works just as well on text files - just make sure to use (for binary) or not use (for text) binmode accordingly.

Writing files

Now that you know how to open and read files learning how to write to them is straighforward. Take a look at the following code:open FILE, ">file.txt" or die $!; print FILE $str; close FILE;Not much is new here. The only thing to observe is the two-argument use of print, the first argument being the FILEHANDLE to write to and the second an expression to be written. The expression can be anything: a scalar, a list, a hash, etc. Appending to a file can be accomplished in exactly the same manner - apart from specifying the appropriate (>>) mode of course.
At this point you are probably thinking that a description of the write is what follows. Actually, as the manual page for write puts it:
Note that write is not the opposite of read. Unfortunately.
Instead write is used to write formatted records to file, a subject outside the scope of this article.

Closing files

Once you are done reading and writing you should close any open filehandles.open FILE1, "file.txt" or die $!; open FILE2, "picture.jpg" or die $!; ... close FILE2; close FILE1;If you forget to close a filehandle Perl will do it for you before your script exists but it is good practice to close yourself what you have opened.
The close command may also fail returning false, eg, if you try to close a closed filehandle. If you want to catch these errors you can check the return value of close and the approriate error message stored in $! as is done in the following example:close FILE or die $!

Summary of perl file handling

The opencloseprint and read commands will allow you to perform most common file operations. However, much more is possible. Apart from opening files you may open pipes to other commands using the | mode and read from them or write to them using the techniques described. This and more in an article to come.

沒有留言:

張貼留言