=begin pod

=TITLE Input/Output

=SUBTITLE File-related operations

Here we present a quick overview of the file-related input/output
operations, detailed documentation can be found in the documentation for the
L<IO|/type/IO> role, as well as the L<IO::Handle|/type/IO::Handle> and
L<IO::Path|/type/IO::Path> types.

=head1 Reading from files

One way to read the contents of a file is to open the file via the C<open>
function with the C<:r> (read) file mode option and slurp in the contents:

    my $fh = open "testfile", :r;
    my $contents = $fh.slurp-rest;
    $fh.close;

Here we explicitly close the file handle using the C<close> method on the
C<IO::Handle> object. This is a very traditional way of reading the
contents of a file. However, the same can be done more easily and clearly
like so:

    my $contents = "testfile".IO.slurp;
    # or in procedural form:
    my $contents = slurp "testfile"

By adding the C<IO> role to the file name string, we are effectively able to
refer to the string as the file object itself and thus slurp in its
contents directly.  Note that the C<slurp> takes care of opening and closing
the file for you.

=head2 Line by line

Of course, we also have the option to read a file line-by-line. The new line
separator (e.g. $*IN.nl-in) will be excluded.

    for 'huge-csv'.IO.lines -> $line {
        # Do something with $line
    }

    # or if you'll be processing later
    my @lines = 'huge-csv'.IO.lines;

=head1 Writing to files

To write data to a file, again we have the choice of the traditional method
of calling the C<open> function -- this time with the C<:w> (write) option
-- and printing the data to the file:

    my $fh = open "testfile", :w;
    $fh.print("data and stuff\n");
    $fh.close;

Or equivalently with C<say>, thus the explicit newline is no longer necessary:

    my $fh = open "testfile", :w;
    $fh.say("data and stuff");
    $fh.close;

We can simplify this by using C<spurt> to open the file in write mode,
writing the data to the file and closing it again for us:

    spurt "testfile", "data and stuff\n";

By default all (text) files are written as UTF-8, however if necessary, an
explicit encoding can be specified via the C<:enc> option:

    spurt "testfile", "latin1 text: äöüß", enc => "latin1";

To append to a file, specify the C<:a> option when opening the file handle
 explicitly,

    my $fh = open "testfile", :a;
    $fh.print("more data\n");
    $fh.close;

or equivalently with C<say>, thus the explicit newline is no longer necessary,

    my $fh = open "testfile", :a;
    $fh.say("more data");
    $fh.close;

or even simpler with the C<:append> option in the call to C<spurt>:

    spurt "testfile", "more data\n", :append;

To explicitly write binary data to a file, open it with the C<:bin> option.
The input/output operations then will take place using the C<Buf> type instead
of the C<Str> type.

=head1 Checking files and directories

Use the C<e> method on an C<IO::Handle> object to test whether the file or
directory exists.

    if "nonexistent_file".IO.e {
        say "file exists";
    }
    else {
        say "file doesn't exist";
    }

It is also possible to use the colon pair syntax to achieve the same thing:

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

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

Similarly to the file existence check, one can also check to see if a path
is a directory.  For instance, assuming that the file C<testfile> and the
directory C<lib> exist, we would obtain from the existence test method C<e>
the same result, namely that both exist:

    say "testfile".IO.e;  # True
    say "lib".IO.e;       # True

However, since only one of them is a directory, the directory test method
C<d> will give a different result:

    say "testfile".IO.d;  # False
    say "lib".IO.d;       # True

Naturally the tables are turned if we check to see if the path is a file via
the file test method C<f>:

    say "testfile".IO.f;  # True
    say "lib".IO.f;       # False

=head1 Getting a directory listing

To list the contents of the current directory, use the C<dir> function. It
returns a list of L<IO::Path> objects.

    say dir;    # "/path/to/testfile".IO "/path/to/lib".IO

To list the files and directories in a given directory, simply pass a path
as an argument to C<dir>:

    say dir "/etc/";    # "/etc/ld.so.conf".IO "/etc/shadow".IO ....

=head1 Creating and removing directories

To create a new directory, simply call the C<mkdir> function with the
directory name as its argument:

    mkdir "newdir";

The function returns the name of the created directory on success and C<Nil>
on failure. Thus the standard Perl idiom works as expected:

    mkdir "newdir" or die "$!";

Use C<rmdir> to remove I<empty> directories:

    rmdir "newdir" or die "$!";

=begin comment
TODO: base on https://github.com/perl6/specs/blob/master/S32-setting-library/IO.pod?
TODO: http://doc.perl6.org/type/IO::Handle has close but no open
=end comment

=end pod

# vim: expandtab shiftwidth=4 ft=perl6
