Raku by Example: Input/Output

The input and output of data in Raku is handled by the IO::Handle which is a class that represents an open file, or an input/output stream.

Opening files

To open a file, use the function open. The basic function usage for open is as follows:

FileObject = open FILENAME, MODE, CONFIG;

FILENAME is the name of the file that you want to interact with, with the file extension included. The mode in the open sub/method tells Raku what you want to do with the file. There are several modes that can be specified:

  • :r (read mode). This mode is used when the information in the file is only meant to be read and not changed in any way. This is the default mode.

  • :w (write mode). This mode is used when the file needs to be altered and information changed or added. It erases the existing file to create a new one.

  • :rw (read-write mode). This mode creates a file if it doesn't exist and overwrites it otherwise.

  • :a (append mode). This mode creates a file if it doesn't exist and append to it otherwise.

CONFIG refers to the configuration parameters the open function accepts:

  • :bin that opens a file in binary mode.
  • :enc('encoding) that associates a file with a given encoding.
  • :chomp that truncates the newline characters when reading file line by line.
my $fh;
$fh = open '/etc/hostname', :r;   # read mode
$fh = open '/etc/hostname', :w;   # write mode
$fh = open '/etc/hostname', :rw;  # read-write mode
$fh = open '/etc/hostname', :a;   # append mode

say $fh;

$fh = open '/etc/hostname', :r, :bin;        # read mode of binary file
$fh = open '/etc/hostname', :r, bin => True; # alternatively

Closing files

To close a file, use the close method/sub on the file handle.

my $fh = open '/etc/hostname'; # open the file
# read/write from/to file
say $fh;
$fh.close;                     # close the file
say $fh;

Testing files

The IO role offers different methods to check properties of files and directories. These methods are:

  • e - check if path exists.
  • d - check if path is an existing directory.
  • f - check if path is an existing file.
  • l - check if path is a symbolic link.
  • r - check if path is accessible.
  • w - check if path is writable.
  • x - check if path is executable.
  • rw - check if path is both readable and writable.
  • rwx - check if path is readable, writable and executable.
  • s - check if path (file) is non-empty.
  • z - check if path (file) has zero size.

All these methods return a Boolean value.

my $file = '/etc/hostname';
my $path = '/home';

say "Path '$file' exists" if  $file.IO.e;
say "$path exists" if $path.IO.d;
say "$file exists" if $file.IO.f;
say "$file is not a symbolic link" unless $file.IO.l;
$ perl6 
Path '/etc/hostname' exists
/home exists
/etc/hostname exists
/etc/hostname is not a symbolic link

Manipulating files

The class IO:Path provides an interface to copy, rename, or delete a file on the hard disk. The method path returns an IO::Path object that allows to perform all these tasks on files.

Among the most frequently methods (or subs) used for working with file paths are:

  • copy - copies a file.
  • rename - renames a file.
  • move - moves a file.
  • chmod - changes a file's permissions.
  • link - creates new link to existing file.
  • symlink - creates a symbolic link.
  • unlink - removes a file, link, or symbolic link.
copy '/etc/hostname', '/tmp/hostname';
IO::Path.new("/etc/hostname").copy('/tmp/HN'); # same as above
$ perl6 file_man01.p6 && ls /tmp/
HN
hostname
rename '/tmp/hostname', '/tmp/new-hostname';
IO::Path.new('/tmp/HN').rename('/tmp/new-HN'); # same as above
$ perl6 file_man02.p6 && ls
new-HN
new-hostname
unlink '/tmp/new-hostname';
IO::Path.new('/tmp/new-HN').unlink;            # same as above
$ perl6 file_man03.p6 && ls

Working with directories

The IO::Path class also provides a few methods (or subs) to work with directories. Some of them are:

  • dir - returns the content of a directory as list of IO::Path objects. Without an argument, dir lists the current working directory.
my @opt-dir = dir '/opt';
my @usr-dir = '/usr'.IO.dir;   # similar as above

say @opt-dir.join(' ');        # join them all 
say @usr-dir[0..^5].join(' '); # join first five
say @usr-dir.first.^name;      # get type of first elem.
$ perl6 work_dir01.p6
/opt/tor-browser /opt/rakudo
/usr/src /usr/sbin /usr/lib32 /usr/lib64 /usr/share /usr/lib
IO::Path
  • chdir - changes the current working directory. The current working directory can be read from the $*CWD variable.
say "Working here --> ", $*CWD;

say "Changing it...";
chdir '/tmp';
'/tmp'.IO.chdir;  # same as above

say "Now here --> ", $*CWD;
$ perl6 work_dir02.p6
Working here --> "/home/luis".IO
Changing it...
Now here --> "/tmp".IO
  • mkdir - creates a new directory.
say "No dir yet!" unless dir('./Docs');

mkdir './Docs/scriptyard';
'./Docs/scriptyard'.IO.mkdir; # same as above

dir('./Docs') ?? say dir('./Docs') !! 'Not dir still'.say;
$ perl6 work_dir03.p6
No dir yet!
("./Docs/scriptyard".IO)
  • rmdir - removes a directory.
.say for dir './Docs/';

my $dir = './Docs/scriptyard';

rmdir $dir;

if dir './Docs/' {
    say "'$dir' is still there.";
}
else {
    say "'$dir' was deleted";
}
$ perl6 work_dir04.p6
"./Docs/scriptyard".IO
'./Docs/scriptyard' was deleted

Streams

Some of the subroutines (print, say, etc.) in the Hello World! section use the values from $*OUT while others (note, warn, etc.) use the values from $*ERR. Other functions such as prompt can use both the $*OUT and $*IN streams. The variables $*OUT (standard output),$*IN (standard input) and $*ERR (standard error) are instances of the IO::Handle class aforementioned.

Reading from streams

Reading a single line

To read a single line from the input stream, use the function get (or its method equivalent, $*IN.get):

my $line = get;
say "Line: ", $line;
$ perl6 single_line.p6
Hello!
Line: Hello!

Reading characters

To get a simple character from the input stream, use the getc subroutine (or $*IN.getc):

my $char = getc;
say "Character: ", $char;
$ perl6 single-char.p6
d
Character: d
$ perl6 single-char.p6
Hello!
Character: H

Reading several lines

To read a list of lines, use the lines subroutine (or $*IN.lines). Given that lines returns a list of lines, it can be looped over or stored directly into an array.

for $*IN.lines -> $line {
	say "Animal: ", $line;
}
$ perl6 several_lines01.p6
Dove
Animal: Dove
Giraffe
Animal: Giraffe
Whale
Animal: Whale
my @lines = lines;
say "[" ~ @lines.join(' | ') ~ "]";
$ perl6 several_lines02.p6
Ln 1 
Ln 2
Ln 3
[Ln 1 | Ln 2 | Ln 3]

Writing to streams

Using print and say to write to file

The use of print and say for printing text to the standard output is discussed in the Hello World! section. Thus only a file handle will be use here.

my $fh = open 'file.txt', :w; # open file for writing
$fh.print("First line\n");    # printing to the file
$fh.close;                    # closing the file handle to save the data

my $fa = open 'file.txt', :a; # open file for appending
$fa.say("Second line");       # printing to the file. No newline needed.
$fa.close;

# Reading the lines from the file
for 'file.txt'.IO.lines {
    say "Line: $_";
}
$ perl6 writing_file.p6
Line: First line
Line: Second line

Formatted strings

Both the printf and sprintf methods/subs print a value in a given format. The sprintf returns a string (Str) while printf writes to a file handle.

As subroutines, the first argument passed to them is a string which describe the format and the rest of arguments are the values that will take the place of the directives. As methods, the invocant is the string describing the format and the arguments are the values which substitute the directives.

Some useful directives:

Directive Description
%% The % character
%c A character
%s A string
%d A signed decimal integer
%f A floating point number

For a complete list of the directives, go to https://docs.perl6.org/routine/sprintf.

printf "The percent sign: %%\n";
printf "Character: %c\n", 35;
printf "String: %s\n", 'Hello!';

"Integer: %d Float: %f\n".printf(12, 3.141593);
$ perl6 format_string.p6
The percent sign: %
Character: #
String: Hello!
Integer: 12 Float: 3.141593

For more information, go to

Back to main