|
In this episode of the Perl tutorial we are going to see how we can handle files. Lots of Perl programs deal with text files such as configuration files, log files so in order to make our knowledge useful it is important at an early stage to learn about file handling. Let's first see how can we write to a file, because that's easier. Before you can write to a file you need to "open" it, asking the operating system (Window, Linux, OSX, etc), to open a channel for your program to "talk to" the file. For this Perl provides the open function. use strict; use warnings; use 5.010; my $filename = 'report.txt'; open(my $fh, '>', $filename) or die "Could not open file '$filename' $!"; say $fh "My first report generated by perl"; close $fh; say 'done'; This is a good working example and we'll get back to it but let's start with a simpler example:
Simple exampleuse strict; use warnings; use 5.010; open(my $fh, '>', 'report.txt'); say $fh "My first report generated by perl"; close $fh; say 'done'; This still needs some explanation. The open function gets 3 parameters. The first one, $fh, is a scalar variable we just defined inside the open() call. We could have defined it earlier but usually it is cleaner to do it inside, even if it looks a bit awkward at first. The second parameter, defines the way we are opening the file. In this case this is the the greater-than sign (>) that means we are opening the file for writing. The third parameter is the path to the file that we would like to open. When this function is called it puts a special sign into the $fh variable. It is called file-handle. We don't care much about the content of this variable, we will just use the variable later. (Actually it is a file-handle object but we don't need to care about that now.) Once the file is open we can use the $fh file-handle in a say() statement. It looks almost the same as the say() in the previous parts of the tutorial, but now the first parameter is the file-handle and there is no(!) comma after it. The say() call above will print the text in the file followed by a newline. Then with the next line we close the file handle. Strictly speaking this is not required in Perl as it will automatically and properly close all the file-handles when the script ends but this can be considered as a good practice. The last line "say 'done'" is only there so the next example will be clearer:
Error handlingLet's take the above example again and replace the filename with a path does not exist. For example write: open(my $fh, '>', 'some_strange_name/report.txt'); If you run the script now you will get an error message: say() on closed file-handle $fh at ... done Actually this is only a warning, the script keeps running and that's why we see the word "done" printed on the screen. Furthermore, we only got the warning because we explicitly asked for warnings with "use warnings". Try commenting out the "use warnings" and see the script still does not create the file but now it does it silently. So you won't even notice it until the customer, or even worse, your boss, complains. Nevertheless it is a problem. We tried to open a file. We failed but then still tried to say() to it something. We'd better check if the open() was successful before proceeding. Luckily the open() call itself returns TRUE on success and FALSE on failure which we would write this: open(my $fh, '>', 'some_strange_name/report.txt') or die; This is the standard "open or die" idiom. Very common in Perl. The "die" is a function call that will throw an exception and thus exit our script. The "open or die" is a logical expression. As you know from the previous part of the tutorial the "or" short-circuits in Perl (as in many other languages). This means that if the left part is TRUE, we already know the whole expression will be TRUE and the right side is not executed. OTOH if the left hand side is FALSE then the right hand side is also executed and the result of that is the result of the whole expression. In this case we use this short-circuit feature to write the expression. If the open() is successful then it returns TRUE and thus the right part never gets executed. The script goes on to the next line. If the open() fails, then it returns FALSE. Then the right side of the "or" is also executed that throws an exception and exits the script. In the above code we don't check the actual resulting value of the logical expression. We don't care. We only used it for the "side effect". If you try the script with the above change you will get an error message: Died at ... and will NOT print "done".
Better error reportingInstead of just calling die without any parameter we could add some explanation what happened.
open(my $fh, '>', 'some_strange_name/report.txt')
or die "Could not open file 'some_strange_name/report.txt'";
will print Could not open file 'some_strange_name/report.txt' ... It is better but at some point someone will change the path to the correct directory ...
open(my $fh, '>', 'correct_directory_with_typo/report.txt')
or die "Could not open file 'some_strange_name/report.txt'";
...but you will still get the old error message. It is probably better to us a variable for the filename: my $filename = 'correct_directory_with_typo/report.txt'; open(my $fh, '>', $filename) or die "Could not open file '$filename'"; Now we get the correct error message but we still don't know why did it fail. Going one step further we can use $! - a built-in variable of Perl - to print out what the operating system told us about the failure: my $filename = 'correct_directory_with_typo/report.txt'; open(my $fh, '>', $filename) or die "Could not open file '$filename' $!"; This will print Could not open file 'some_strange_name/report.txt' No such file or directory ... That's much better. With this we got back to the original example.
Greater-than?That greater-than sign in the open call might be a bit unclear but if you are familiar with command line redirection then this can be familiar to you too. Otherwise just think about it as an arrow showing the direction of the data-flow: into the file on the right hand side.
ExerciseAs an exercise write a script that will ask the name of the user and create a file called report.txt containing the name of the user. An advanced exercise would be to ask for the name of the user and the name of the file and then create that file.
Next partThe next part should deal with opening a file for reading.
Perl tutorial and video courseFor further articles see the Beginner Perl Maven tutorial book and video course.In the comments, please wrap your code snippets within <pre> </pre> tags and use spaces for indentation. blog comments powered by Disqus |
Follow me: