Camelia

Perl 6 files

While learning the internal logic and syntax of a language can be interesting, without I/O, especially without reading and writing files, it won't be too useful.

It is quite important for me that the Perl 6 Maven site will present Perl 6 in a way, that already provides the tools to you to use it.

So this time, we are going to deal with files.

Note! This site is about Perl 6, the future version of Perl.
If you are looking for a solution for the current production version of Perl 5, please check out the Perl 5 tutorial.

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 one or two parameters:

The name of the file and the mode. The mode can be :r for reading, :w for writing, and :a for appending. It defaults to reading so we can write the following code:

$fh = open $filename;

Which is the same as this one:

$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.

use v6;

my $filename = "data.txt";

my $fh = open $filename;
my $line = $fh.get;
say $line;

Important to note, especially to Perl 5 programmers, that the newline from the end of the line is removed. That is, the get method autochomps.

Process a file line by line

The lines() method of the filehandle will return all the lines lazily. This means, in the following code the file is read line-by-line into the $line variable by the for loop. It won't start by reading all the lines and iterating over them. Thus, this is a useful construct even on huge files.

use v6;

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

my $fh = open $filename, :r;
for $fh.lines -> $line {
    say $line;
}

Writing to a file

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

use v6;

my $filename = "temp.txt";

my $fh = open $filename, :w;
$fh.say("hello world");
$fh.print("second line\n");
$fh.close;

While theoretically it is not required to close the file handle, it is a good practice, and besides, currently if you don't call close, the file won't be saved.

Appending to a file

If we open a file for writing using the :w modifier, the file automatically gets truncated to the empty file and the only content it will have is what we added to it.

Sometime, for example in log files, we would like to keep the original file intact and add lines of data at the end of it. For that purpose we can open the file with the :a (append) modifier.

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.chars;
say $data;

The chars method, returns the number of characters in the string. As you can see for this operation to work, you don't need to open the file.

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 surprising for Perl 5 developers. It reads the entire file in the first element of the array:

use v6;

my $filename = 'data.txt';

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

The elems method return the number of elements in the array.

If you would like to read all the lines in the elements of the array the lines() functions is needed:

use v6;

my $filename = 'authors.txt';

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

my @lines = lines $filename;
say @lines.elems;              # 1 !!!

The problem with that code is that the lines function, if applied to a plain scalar, will return the lines in that string. Basically splitting the string at newlines. Therefore, in order to use lines, we need the file handle.

The long solution looks like this:

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

However, there is a nicer solution. We can turn the name of the file into an IO object and we can use the lines method on that object:

my @all = $filename.IO.lines;
say @all.elems;

Of course, if we only wanted to know the number of lines in the file, we could stack the elems method at the end:

say $filename.IO.lines.elems;

The Perl 6 Tricks and Treats newsletter has been around for a while. If you are interested to get special notification when there is new content on this site, it is the best way to keep track:
Email:
Full name:
This is a newsletter temporarily running on my personal site (szabgab.com) using Mailman, till I implement an alternative system in Perl 6.
Gabor Szabo
Written by Gabor Szabo

Published on 2012-08-16



Comments

In the comments, please wrap your code snippets within <pre> </pre> tags and use spaces for indentation.
comments powered by Disqus

Perl 6 Tricks and Treats newsletter

Register to the free newsletter now, and get updates and news.
Email:
Name: