role IO::FileTestable

Common role for paths that can be tested for filesystem metadata

role IO::FileTestable does IO { }

Methods

File Test operators

-e -f

The -e and -f file test operators do not exist in Perl 6. Use instead :e and :f.

-M -A -C

The -M, -A and -C file test operators do not exist in Perl 6, use instead the modified, accessed and changed methods instead.

:e :d :f :l :r :w :x :s :z

:e Exists
:d Directory
:f File
:l Symbolic link
:r Readable
:w Writable
:x Executable
:s Size
:z Zero size

Usage:

If you have a string - a path to something in the filesystem:

if "path/to/file".IO ~~ :e {
    say 'file exists';
}

my $file = "path/to/file";
if $file.IO ~~ :e {
    say 'file exists';
}

Instead of the colonpair syntax, you can use method calls too:

if 'path/to/file'.IO.e {
    say 'file exists';
}

If you already have an IO object in $file, either by creating one yourself, or by getting it from another subroutine, such as dir, you can write this:

my $file = "path/to/file".IO;
if $file ~~ :e {
    say 'file exists';
}

File timestamp retrieval

There are also 3 methods for fetching the 3 timestamps of a file (inode), on Operating Systems where these are available:

method modified

Return an Instant object representing the timestamp when the file was last modified.

say "path/to/file".IO.modified;   #  e.g. Instant:1424089165

To obtain a human-readable form of the timestamp, use a DateTime object:

say DateTime.new("path/to/file".IO.modified);  # e.g. 2015-02-16T12:18:50Z

or more readably:

my $modification_instant = "path/to/file".IO.modified;
my $modification_time = DateTime.new($modification_instant);
say $modification_time;         # e.g. 2015-02-16T12:18:50Z

method accessed

Return an Instant object representing the timestamp when the file was last accessed.

say "path/to/file".IO.accessed;   #  e.g. Instant:1424353577

To obtain a human-readable form of the timestamp, use a DateTime object:

say DateTime.new("path/to/file".IO.accessed);  # e.g. 2015-02-19T13:45:42Z

or more readably:

my $access_instant = "path/to/file".IO.accessed;
my $access_time = DateTime.new($access_instant);
say $access_time;         # e.g. 2015-02-19T13:45:42Z

method changed

Return an Instant object representing the timestamp when the inode was last changed.

"path/to/file".IO.changed;        #  e.g. Instant:1424089165

To obtain a human-readable form of the timestamp, use a DateTime object:

say DateTime.new("path/to/file".IO.changed);  # e.g. 2015-02-16T12:18:50Z

or more readably:

my $change_instant = "path/to/file".IO.changed;
my $change_time = DateTime.new($chnge_instant);
say $change_time;         # e.g. 2015-02-16T12:18:50Z

Related roles and classes

See also the related role IO and the related classes IO::Handle and IO::Path.

Type graph

Below you should see a clickable image showing the type relations for IO::FileTestable that links to the documentation pages for the related types. If not, try the PNG version instead.

perl6-type-graph IO::FileTestable IO::FileTestable IO IO IO::FileTestable->IO

Routines supplied by role IO

IO::FileTestable does role IO, which provides the following methods:

sub print

Print the given text on $*OUT (standard output), e.g.:

print "Hi there!\n";   # Hi there!

Note that the print function does not (in contrast to some other languages) append a newline character to the text. Thus the following code

print "Hi there!";
print "How are you?";

displays

Hi there!How are you?

To print text implicitly including the trailing newline character, use say.

sub say

Print the given text, followed by a newline "\n" on $*OUT (standard output).

With say, the example code as mentioned in the print section will be displayed as the user likely intended:

say "Hi there!";
say "How are you?";

displays

Hi there!
How are you?

say prints non-Str objects by calling their .gist method before printing. Hence the following say statements for the respective containers are equivalent:

    my @array = qw{1 2 3 4};
    say @array;       # 1 2 3 4␤
    say @array.gist;  # 1 2 3 4␤

    my %hash = "a" => 1, "b" => 2, "c" => 3;
    say %hash;        # a => 1, b => 2, c => 3␤
    say %hash.gist;   # a => 1, b => 2, c => 3␤

sub note

Print the given text, followed by a newline "\n" on $*ERR (standard error). Before printing, call the .gist method on any non-Str objects.

note is effectively say, only it writes its output to the standard error stream. For instance:

    if ("path/to/pirate/treasure".IO.e) {
	say "Found pirate treasure!";
    }
    else {
	note "Could not find pirate treasure.  Are you sure it exists?";
    }

will report (on the standard output stream) that treasure has been found if it exists or will note on the error stream that it couldn't be found if it doesn't exist.

sub dd

The Tiny Data Dumper. This function takes the input list of variables and notes them (on $*ERR) in an easy to read format, along with the name of the variable. Thus,

my $a = 42;
my %hash = "a" => 1, "b" => 2, "c" => 3;
dd %hash, $a;

prints

%hash = ("a" => 1, "c" => 3, "b" => 2).hash, $a = 42

to the standard error stream.

This is in spirit similar to Perl 5's Data::Dumper module.

sub prompt

sub prompt($msg)

Prints $msg to standard output and waits for the user to type something and finish with an ENTER. Returns the string typed in without the trailing newline.

my $name = prompt("Hi, what's your name? ");

sub open

my $fh = open(IO::Path() $path, :$r, :$w, :$a, :$rw,
              :$bin, :$enc, :$nl, :$chomp)

Opens the $path (by default in text mode) with the given options, returning an IO::Handle object.

File mode options

  • read-only mode, :r

  • Open the file as read only, e.g.:

    my $fh = open("path/to/file", :r);
    

    This is the default mode for open.

    Write-related methods on the returned IO::Handle object will fail in this mode:

    my $fh = open("test");   # the file "test" already exists
    spurt $fh, "new text\n";
    Failed to write bytes to filehandle: bad file descriptor
    
  • write-only mode, :w

  • Open the file for writing, creating it if it doesn't exist or overwriting the file if it does exist, e.g.:

    my $fh = open("path/to/file", :w);
    

    Read-related methods will fail in this mode:

    my $fh = open("test", :w);
    spurt $fh, "stuff\n";
    spurt $fh, "more stuff\n";
    $fh.seek(0, 0);   # return to the start of the file
    $fh.get();        # Reading from filehandle failed: bad file descriptor
    
  • read-write mode, :rw

  • Open the file for reading and writing, creating the file if it doesn't exist or overwriting the file if it already exists.

    my $fh = open("path/to/file", :w);
    
  • append mode, :a

  • Open the file for appending. If the file does not exist, create it. If the file already exists, append data to it.

    my $fh = open("path/to/file", :a);
    

    Encoding options

  • binary mode, :bin

  • Open the file in binary mode (byte mode):

    my $fh = open("path/to/file", :bin);
    

    A file opened with :bin may still be processed line-by-line, but IO will be in terms of Buf rather than Str types. Default is False, implying text semantics.

  • text mode encoding, :enc

  • The encoding to use if opened in text mode.

    # open explicitly as utf8
    my $fh = open("path/to/file", enc => "utf8");
    my $fh = open("path/to/file", enc => "utf-8");  # this form also works
    # open with latin1 encoding
    my $fh = open("path/to/file", enc => "latin1");
    

    Defaults to "Unicode", which implies figuring out which actual UTF is in use, either from a BOM or other heuristics. If heuristics are inconclusive, UTF-8 will be assumed. (No 8-bit encoding will ever be picked implicitly.) There exists no valid option with the name "Unicode", so the following will result in an error:

    my $fh = open("path/to/file", enc => "Unicode");
    

    This is because one needs to specify a specific unicode encoding, e.g. "utf8".

    Newline options

  • end-of-line (EOL) marker, :nl

  • The marker used to indicate the end of a line of text. Only used in text mode. Defaults to "EOL", which implies accepting any combination of "\n", "\r\n" or "\r" or any other Unicode character that has the Zl (Separator, Line) property.

    # explicitly use CR-LF as EOL character
    my $fh = open("path/to/file", nl => "\r\n");
    
  • chomp mode, :chomp

  • Whether or not to remove newline characters from text obtained with .lines and .get. Defaults to True.

    # don't remove newline characters from input
    my $fh = open("path/to/file", chomp => False);
    say $fh.get();     # returns line including newline char
    

    method close

    To close an open file handle, simply call its close method:

    my $fh = open("path/to/file");
    # ... do stuff with the file
    $fh.close;
    

    It is also possible to call this as a sub, thus the example above can be written equivalently like so:

    my $fh = open("path/to/file");
    # ... do stuff with the file
    close $fh;
    

    When a file was opened for writing, closing it is important to ensure that all contents are actually written to the file.

    sub slurp

    Slurps the contents of the entire file into a Str (or Buf if :bin). Accepts :bin and :enc optional named parameters, with the same meaning as /open(). The routine will fail if the file does not exist, or is a directory.

    # read entire file as (Unicode) Str
    my $text_contents   = slurp "path/to/file";
    
    # read entire file as Latin1 Str
    my $text_contents   = slurp "path/to/file", enc => "latin1";
    
    # read entire file as Buf
    my $binary_contents = slurp "path/to/file", :bin;
    

    sub spurt

    sub spurt ($where, $what,
        Str  :$enc        = $*ENC,
        Bool :append      = False,
        Bool :$createonly = False,
        --> Bool ) is export
    

    Writes the indicated contents (2nd positional parameter, $what) to the location indicated by the first positional parameter, $where (which can either be a string or an IO::Path object). To write to an IO::Handle, use the print method.

    If a file needs to be opened for writing, it will also be closed. Returns True on success, or the appropriate Failure if something went wrong.

    These named parameters are optional and only have meaning if the first positional parameter was not an IO::Handle:

    Options

  • :enc

  • The encoding with which the contents will be written.

  • :append

  • Boolean indicating whether to append to a (potentially) existing file. If the file did not exist yet, it will be created. Defaults to False.

  • :createonly

  • Boolean indicating whether to fail if the file already exists. Defaults to False.

    Examples

    # write directly to a file
    spurt "path/to/file", "default text, directly written";
    
    # write directly with a non-Unicode encoding
    spurt "path/to/latin1_file", "latin1 text: äöüß", enc => "latin1";
    
    # append to a pre-existing file
    spurt "file_already_exists", "some text";
    spurt "file_already_exists", "new text", :append;
    slurp "file_already_exists";   # some text␤new text
    
    # fail when writing to a pre-existing file
    spurt "file_already_exists", "new text", :createonly;
    File 'test' already exists, and :createonly was specified
    

    sub run

    sub run(*@args ($, *@)) returns Proc
    

    Runs an external command without involving a shell (if possible).

    See Proc for more details, for example on how to capture output.

    sub shell

    sub shell($cmd) returns Proc
    

    Runs a command through the system shell. All shell meta characters are interpreted by the shell, including pipes, redirects, environment variable substitutions and so on. See run if you don't want that.

    The return value is of type Proc.

    shell 'ls -lR | gzip -9 > ls-lR.gz';
    

    See Proc for more details, for example on how to capture output.