Perl 6 files

As part of the Perl 6 Tricks and Treats newsletter we are dealing with reading and writing files.


This entry was first sent out as part of the Perl 6 Tricks and Treats. Visit here to subscribe.

Welcome back to the Perl 6 Tricks and Treats

Sorry for the random scheduling of these posts. Sometimes I am too busy at clients, other times I am busy with Padre, my main open source project.

If you don't know about it yet Padre is and IDE for Perl. It was originally started as an IDE for Perl 5 but soon it turned out to be a good platform to become an IDE for Perl 6 as well.

It is interesting though understandable that most of the beginner-friendly features of Padre are driven by the Perl 6 plugin development. After all the Padre developers know Perl 5 quite well but we are still only at the beginning of our Perl 6 learning curve.

Ahmad M. Zawawi (azawawi) invested a lot of energy and created a very useful Perl 6 plugin for Padre and a few nice blog entries as well:

So if you are not yet convinced that you should give Padre and its Perl 6 plugin a try, take a look at his posts:

Perl 6 support and Ecliptic

Perl 6 Quick Fixes in Action

What's new with Padre Perl 6?

Perl 6 files

In the previous posting I wrote about arrays. There is a lot more one could do with array in Perl 6 but lets look at the file operations now as without reading and writing files coding might not be that useful.

Open a file

As in other high level languages one has to open a file in order to read from it or to write to it. In Perl6 it is done by the open() function imported from the IO class. It can receive several parameter but the two are very important: The name of the file and the mode. In order to open a file for reading the mode need to be :r. The function either returns a file handle that should be placed in a scalar variable or returns undef in case of failure.

$fh = open $filename, :r

Once we have an open file handle we can use the get method ($fh.get) to read one line from the given file.

One could read many lines using consecutive calls to the get method but there are better ways to do that.

Currently I think Rakudo throws an exception if the file cannot be opened but I think the spec says that it should just return undef.

The specifications of all the IO of Perl 6 can be found in S32-setting-library/IO.pod

use v6;

my $filename = "data.txt";

if (my $fh = open $filename, :r) {
    my $line = $fh.get;
    say $line;
} else {
    say "Could not open '$filename'";
}

Process a file line by line

The lines() method of the file handle can return either all the lines, some of the lines. As it does it lazily in the code below we get an iterator behavior so the file is read line-by-line into the $line variable by the for loop.

use v6;

my $filename = "path/to/data.txt";

if (my $fh = open $filename, :r) {
    for $fh.lines -> $line {
        say $line;
    }
} else {
    say "Could not open '$filename'";
}

Writing to a file

In order to write to a file first we need to open the file for writing with the :w mode. If this is successful we get back a filehandle on which we can use the regular output methods such as print(), say() or printf().

use v6;

my $filename = "temp.txt";

if (my $fh = open $filename, :w) {
    $fh.say("hello world");
}

Other modes for opening files

So far I mentioned the read (:r) and the (:w) write mode of opening files but actually this is a bit of a speculation as at the time of the writing this has not been included in the specifications yet.

They are both working in Rakudo along with the append (:a) mode but were not specified yet.

slurp

Perl 6 has a built in function to slurp in files, that is to read the contents of a whole file into a scalar variable.

use v6;

my $filename = 'data.txt';

my $data = slurp $filename;
say $data.bytes;               # print size of file in bytes

lines of file

Unlike the Perl 5 implementation of the slurp() function in Perl 6 it is not aware of its environment so the following code might be a bit surprisings for Perl 5 developers as it reads the entire file in the first element of the array:

my @content = slurp $filename; say @content.elems; # 1

If one wants to read all the lines in the elements of the array the lines() functions is needed:

use v6;

my $filename = 'data.txt';

# reads all the content of the file in the first element of the array!
my @content = slurp $filename;
say @content.elems;

my @rows = lines $filename;
say @rows.elems;

Conclusion

That's it for now. I plan to write a few more entries in the coming 2 weeks. Stay tuned.


This entry was first sent out as part of the Perl 6 Tricks and Treats. Visit here to subscribe.