Skip to content
This repository
tree: 2230db7a08
Fetching contributors…

Cannot retrieve contributors at this time

file 1017 lines (651 sloc) 25.904 kb

DRAFT: Synopsis 32: Setting Library - IO

    The authors of the related Perl 5 docs
    Rod Adams <rod@rodadams.net>
    Larry Wall <larry@wall.org>
    Aaron Sherman <ajs@ajs.com>
    Mark Stosberg <mark@summersault.com>
    Carl Mäsak <cmasak@gmail.com>
    Moritz Lenz <moritz@faui2k3.org>
    Tim Nelson <wayland@wayland.id.au>
    Daniel Ruoso <daniel@ruoso.com>
    Lyle Hopkins <webmaster@cosmicperl.com>

    Created: 19 Feb 2009 extracted from S29-functions.pod; added stuff from S16-IO later

    Last Modified: 06 July 2012
    Version: 15

The document is a draft.

If you read the HTML version, it is generated from the Pod in the specs repository under https://github.com/perl6/specs/blob/master/S32-setting-library/IO.pod so edit it there in the git repository if you would like to make changes.

The most common IO operations are print and say for writing and lines and get for reading. All four are available as subroutines (defaulting to the $*OUT and $*ARGFILES file handles) and as methods on file handles.

File handles are of type IO::Handle, and can be created with &open. Paths are generally passed as strings or IO::Path objects.

&dir returns IO::File and IO::Dir objects, which are subclasses of IO::Path.

              default handle
    routine   for sub form    purpose
    =======   ===========     =======
    print     $*OUT           string-based writng
    say       $*OUT           string-based witing
    get       $*ARGFILES      read a line (Str)
    lines     $*ARGFILES      read all lines (Str)
    read                      binary reading (Buf)
    write                     binary writing (Buf)

File tests are performed through IO::Path objects.

    multi open (Str $name,
        Bool :$rw = False,
        Bool :$bin = False,
        Str  :$enc = "Unicode",
        Any  :$nl = "\n",
        Bool :$chomp = True,
        ...
        --> IO
    ) is export returns IO::Handle

A convenience function that hides most of the OO complexity. It will only open normal files. Text is the default. Note that the "Unicode" encoding 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.) A file opened with :bin may still be processed line-by-line, but IO will be in terms of Buf rather than Str types.

TODO: document read/write/append modes (:r, :w, :a)

    multi dir($directory = '.', Mu :$test = none('.', '..')) { ... }

Returns a lazy list of file names in the $directory. By default the current and the parent directory are excluded, which can be controlled with the $test named parameter. Only items that smart-match against this test are returned.

The return value is a list of IO::File and IO::Dir objects.

    multi multi note (*@LIST --> Bool)

Does a "say" to $*ERR, more or less. Like warn, it adds a newline only if the message does not already end in newline. Unlike warn, it is not trappable as a resumable exception because it outputs directly to $*ERR. You can suppress notes in a lexical scope by declaring:

    only note(*@) {}
    multi slurp (IO $fh = $*ARGFILES,
        Bool :$bin = False,
        Str  :$enc = "Unicode",
        --> Str|Buf
    )
    multi slurp (Str $filename,
        Bool :$bin = False,
        Str  :$enc = "Unicode",
        --> Str|Buf
    )

Slurps the entire file into a Str (or Buf if :bin) regardless of context. (See also lines.)

The routine will fail if the file does not exist, or is a directory.

    multi spurt (IO $fh,
        Str   $contents,
        Str  :$enc = $?ENC,
        Bool :append = False,
    )
    multi spurt (IO $fh,
        Buf   $contents,
        Bool :append = False,
    )
    multi spurt (Str $filename,
        Str   $contents,
        Str  :$enc = $?ENC,
        Bool :append = False,
    )
    multi spurt (Str $filename,
        Buf   $contents,
        Bool :append = False,
    )

Opens the file for writing, dumps the contents, and closes the file.

This routine will fail if the file exists, unless the :append flag is set, in which case it will instead add the given contents at the end of the file.

The routine will also fail with the corresponding exception if there was any other error in opening, writing, or closing.

    multi sub chdir(Str:D)
    multi sub chdir(IO::Path::D)

Changes the current working directory to the new value. Fails on error.

    role IO { };

The base role only tags that this is an IO object for more generic purposes. It doesn't specify any methods or attributes.

    class IO::Handle does IO { ... }

A handle of a file, pipe or anything else that supports reading or writing like a file.

    method get() returns Str:D

Reads and returns one line from the handle. Uses input-line-separator to determine where a line ends.

    method lines($limit = Inf)

Returns a lazy list of lines read via the get method, limited to $limit lines.

    method getc (IO::Handle:D: Int $chars = 1 --> Str)

Reads $chars and returns them

    method print (IO::Handle:D: *@LIST --> Bool)
    multi print (*@LIST --> Bool)

Stringifies each element, concatenates those strings, and sends the result to the output. Returns Bool::True if successful, Failure otherwise.

The compiler will warn you if use a bare sub print without arguments. (However, it's fine if you have an explicit argument list that evaluates to the empty list at runtime.)

    print;             # warns
    if $_ { print }    # warns
    if $_ { print() }  # ok, but does nothing
    if $_ { print () } # ok, but does nothing
    method say (IO::Handle:D: *@LIST --> Bool)
    multi say (*@LIST --> Bool)

This is identical to print() except that it stringifies its arguments by calling .gist on them and auto-appends a newline after the final argument.

    Was:    print "Hello, world!\n";
    Now:    say   "Hello, world!";

As with print, the compiler will warn you if you use a bare sub say without arguments.

    method printf (Str $fmt, *@LIST --> Bool)
    multi printf (IO::Handle:D: Str $fmt, *@LIST --> Bool)

Output through Str.sprintf. See S32::Str for details.

    method write(IO::Handle:D: Buf $buf --> Int)

Tries to write $buf. The actual number of bytes written is returned. It might return unthrown failures, to be specified by each IO implementation.

This is "raw" write. $buf contains plain octets. If you want to write a Str, you should .encode it first, or use "print" or other IO::Writeable::Encoded methods.

    method slurp()

Reads all the remaining contents of the handle into a Str (or a Buf if the handle was opened with :bin).

    method t() returns Bool:D

Returns True if the handle is opened to a tty.

    method p() returns Bool:D

Returns True if the handle is opened to a pipe.

    method eof() returns Bool:D

Returns True if the handle is exhausted.

method seek(Int $position, Int $whence --> Bool)

Position this stream into $position. The meaning of this position is always in "octets".

Fails if the handle is not seekable.

TODO: make $whence an Enum

    method tell() returns Int:D:

Returns the current raw position in the stream in number of "octets".

    method ins( --> Int)

Returns the number of lines that have been read with get.

    method input-line-separator( --> Str) is rw

This regulates how "get" and "lines" behave.

The input line (record) separator, newline by default. This influences Perl's idea of what a ``line'' is. Works like awk's RS variable, including treating empty lines as a terminator if set to the null string. (An empty line cannot contain any spaces or tabs.) You may set it to a multi-character string to match a multi-character terminator, or to Nil to read through the end of file. Setting it to "\n\n" means something slightly different than setting to "", if the file contains consecutive empty lines. Setting to "" will treat two or more consecutive empty lines as a single empty line. Setting to "\n\n" will blindly assume that the next input character belongs to the next paragraph, even if it's a newline.

You may also set it to a regular expression. The value of $/ will be (temporarily) set to the matched separator upon input, if you care about the contents of the separator.

Closes the handle. Fails on error.

    role IO::FileTests does IO { ... }

Provides ways to inspect a file or path without opening it.

If you apply that role to a class, that class must provide a path method which IO::FileTests' method will call to obtain the path to test. This path method must return a Str:D.

The methods are typically only one letter long (for now; perl 5 tradition strikes) and are summarized in the following table:

    M  Test performed
    =  ==============
    r  $.path is readable by effective uid/gid.
    w  $.path is writable by effective uid/gid.
        x  $.path is executable by effective uid/gid.
    o  $.path is owned by effective uid.

    R  $.path is readable by real uid/gid.
    W  $.path is writable by real uid/gid.
    X  $.path is executable by real uid/gid.
    O  $.path is owned by real uid.

    e  $.path exists.
    s  $.path has a size > 0 bytes

    f  $.path is a plain file.
    d  $.path is a directory.
    l  $.path is a symbolic link.
    p  $.path is a named pipe (FIFO)
    S  $.path is a socket.
    b  $.path is a block special file.
    c  $.path is a character special file.

    u  $.path has setuid bit set.
    g  $.path has setgid bit set.
    k  $.path has sticky bit set.

TODO: methods created, accessed, modified

    class IO::Path is Cool does IO::FileTest { }

Holds a path of a file or directory. The path is generally divided into three parts, the file system, directory and base name.

On Windows, the file system is a drive letter like C:. Relative paths never have a file system part. On UNIX-based systems, the file system part is empty.

The base name is name of the file or directory that the IO::Path object represents, and the directory is the part of the path leading up to the base name.

    path            file system   directory  base name
    /usr/bin/gvim                 /usr/bin   gvim   
    /usr/bin/                     /usr       bin
    C:\temp\f.txt  C:             temp       f.txt

Returns the path (file system, directory and base name joined together) as a string.

Returns the file system part of the path

Returns the directory part of the path

Returns the base name part of the path

Stringifies to the base name.

    class IO::File is IO::Path { ... }

Represents a path that is known to be a plain file (not a directory), at least at the time when the object was created.

    class IO::Dir is IO::Path { ... }

Represents a path that is known to be a directory, at least at the time when the object was created.

Everything below this point hasn't been reviewed properly

    role IO::Socket {
        has %.options;
        has Bool $.Listener;
        ...
    }

Accessing the %.options would on Unix be done with getsockopt(2)/setsockopt(2).

The $.Listener attribute indicates whether the socket will be a listening socket when opened, rather than indicating whether it is currently listening.

    method new(
        :$Listener, # initialises $.Listener
    )

The initial value of the $.Listener attribute is defined according to the following rules:

 * If $Listener is passed to .new(), then that value is used
 * If neither a local address nor a remote address are passed in, throw an exception
 * If no remote address is passed, then $.Listener is set to SOMAXCONN
 * If no local address is used, then $Listener is set to 0
 * If both local and remote addresses are used, throw an exception that asks people to
   specify $Listener
    method open()

If $.Listener is true, does a bind(2) and a listen(2), otherwise does a connect(2).

It's end-user use case is intended for the case where NoOpen is passed to .new(). .new() itself will presumably also call it.

    method close()

Implements the close() function from IO::Closeable by doing a shutdown on the connection (see below) with @how set to ('Readable', 'Writeable').

    method shutdown(Str @how)

Does a shutdown(2) on the connection. See also IO::Readable.isReadable and IO::Writeable.isWriteable.

$how can contain 1 or more of the strings 'Readable' and 'Writeable'.

    method accept( --> IO::Socket)

Implements the IO::Readable interface by doing a recv(2).

Implements the IO::Writeable interface by doing a send(2).

    class IO::Socket::INET does IO::Socket {
        has Str $.proto = 'TCP';
        has Str $.host;
        has Int $.port;
        has Str $.localhost;
        has Int $.localport;
        ...
    }
    multi method new(:$host!, :$port, *%attributes) { ... }
    multi method new(:$localhost!, :$localport, :$listen! *%attributes) { ... }

Creates a new socket and opens it.

This role indicates that this object actually represents an open file descriptor in the os level.

File descriptors are always native integers, conforming to C89.

Everything below this point should be considered as mere ideas for future evolution, not as things that a compiler write should implement unquestioningly.

  • The mode of the file and the uids and gids of the user
  • ACLs (access control lists)
  • read-only filesystems

There may be other reasons you can't actually read, write, or execute the file. Such reasons may be for example network filesystem access controls and unrecognized executable formats.

Also note that, for the superuser on the local filesystems, the :r, :R, :w, and :W tests always return 1, and :x and :X return 1 if any execute bit is set in the mode. Scripts run by the superuser may thus need to do a stat to determine the actual mode of the file, or temporarily set their effective uid to something else.

You can test multiple features using junctions:

  if $filename.IO ~~ :r & :w & :x  {...}

This is a basic abstraction; for better control, use the operating-system specific interfaces, over which this is a thin veneer.

    class IO::ACL {
        has Str $.type; # "User", "Group", "Everyone", ???
        has Str $.id; # username or groupname; unused for $type eq "Everyone"
        has %.permissions;
                # Unsupported values may (or may not) throw
                # UnsupportedPermission when set or read
        has Path $.owningObject;
        ...
    }

The permissions used in %permissions are:

Should be supported by all filesystems as an item to read from the hash for the group "Everyone".

Should be supported by all filesystems as an item to read from the hash for the group "Everyone".

Supported on most Unix systems, anyway. Windows should be able to guess when this is read, and throw an exception if written to.

An ACL of User,fred,Default sets the user "fred" to be the owner of the file. This can be done with groups too. Works on Unix, at least.

The $.owningObject attribute of ACL shows what the ACL is set on. On a Windows system, this can be a parent directory, as permissions are inherited.

    class IO::Pipe does IO::Streamable does IO::Readable does IO::Writable {
        ...
    }

Will need to set IO::Readable.isReadable and IO::Writable.isWriteable depending on opening method.

If the file handle came from a piped open, close will additionally return Failure (aliased to $!) if one of the other system calls involved fails, or if the program exits with non-zero status. The exception object will contain any pertinent information. Closing a pipe also waits for the process executing on the pipe to complete, in case you want to look at the output of the pipe afterwards, and implicitly puts the exit status value into the Failure object if necessary.

    method to(Str $command, *%opts --> Bool)
    method to(Str *@command, *%opts --> Bool)

Opens a one-way pipe writing to $command. IO redirection for stderr is specified with :err(IO) or :err<Str>. Other IO redirection is done with feed operators. XXX how to specify "2>&1"?

    method from(Str $command, *%opts --> Bool)
    method from(Str *@command, *%opts --> Bool)

Opens a one-way pipe reading from $command. IO redirection for stderr is specified with :err(IO) or :err<Str>. Other IO redirection is done with feed operators. XXX how to specify "2>&1"?

    method pair(--> List of IO::Pipe)

A wrapper for pipe(2), returns a pair of IO objects representing the reader and writer ends of the pipe.

   ($r, $w) = IO::Pipe.pair;

    multi chown ($uid = -1, $gid = -1, *@files --> Int)

Changes the owner (and group) of a list of files. The first two elements of the list must be the numeric uid and gid, in that order. A value of -1 in either position is interpreted by most systems to leave that value unchanged. Returns the number of files successfully changed.

    $count = chown $uid, $gid, 'foo', 'bar';
    chown $uid, $gid, @filenames;

On systems that support fchown, you might pass file handles among the files. On systems that don't support fchown, passing file handles produces a fatal error at run time.

Here's an example that looks up nonnumeric uids in the passwd file:

   $user = prompt "User: ";
   $pattern = prompt "Files: ";

   ($login,$pass,$uid,$gid) = getpwnam($user)
       or die "$user not in passwd file";

   @ary = glob($pattern);      # expand filenames
   chown $uid, $gid, @ary;

On most systems, you are not allowed to change the ownership of the file unless you're the superuser, although you should be able to change the group to any of your secondary groups. On insecure systems, these restrictions may be relaxed, but this is not a portable assumption. On POSIX systems, you can detect this condition this way:

    use POSIX qw(sysconf _PC_CHOWN_RESTRICTED);
    $can-chown-giveaway = not sysconf(_PC_CHOWN_RESTRICTED);

Changes the permissions of a list of files. The first element of the list must be the numerical mode, which should probably be an octal number, and which definitely should not be a string of octal digits: 0o644 is okay, 0644 is not. Returns the number of files successfully changed.

    $count = chmod 0o755, 'foo', 'bar';
    chmod 0o755, @executables;
    $mode = '0644'; chmod $mode, 'foo';      # !!! sets mode to --w----r-T
    $mode = '0o644'; chmod $mode, 'foo';     # this is better
    $mode = 0o644;   chmod $mode, 'foo';     # this is best
    $node.stat(Bool :$link); # :link does an lstat instead

Returns a stat buffer. If the lstat succeeds, the stat buffer evaluates to true, and additional file tests may be performed on the value. If the stat fails, all subsequent tests on the stat buffer also evaluate to false.

    role IO::Socket::Unix does IO::Socket {
        has Str $.RemoteAddr, # Remote Address
        has Str $.LocalAddr,  # Local Address
    }
    method new(
        Str  :$RemoteAddr,
        Str  :$LocalAddr,

        Bool :$Listener,   # Passed to IO::Socket.new()

        Bool :$Blocking,   # Passed to IO::Streamable.new()
        Bool :$NoOpen,     # Passed to IO::Streamable.new()

        --> IO::Socket::Unix
    ) {...}
    method pair(Int $domain, Int $type, Int $protocol --> List of IO)

A wrapper for socketpair(2), returns a pair of IO objects representing the reader and writer ends of the socket.

   use IO::Socket;
   ($r, $w) = IO::Socket::Unix.pair(AF_UNIX, SOCK_STREAM, PF_UNSPEC);

Indicates that this object can perform standard posix IO operations. It implies IO::Readable and IO::Writeable.

Available only as a handle method.

    multi prompt (Str $prompt --> Str)

Should there be an IO::Interactive role?

Gone, see eoi IO::Seekable.

See IO::Handle.

Should be implemented by an external library.

Use stat with the :link option.

Changed to .path, but we haven't gotten around to specifying this on all of them.

The .name method returns the name of the file/socket/uri the handle was opened with, if known. Returns Nil otherwise. There is no corresponding name() function.

Gone, see Pipe.pair

Gone. (Note: for sub-second sleep, just use sleep with a fractional argument.)

Gone, see IO::Socket.close(), $IO::Readable.isReadable, and $IO::Writeable.isWriteable

Gone, see Socket.pair

Gone, see IO::Readable.read().

Gone, see IO::Writeable.read().

Gone, see Path.times.

Indicates that this object performs buffering. The management of the buffer is completely implementation specific.

Flushes the buffers associated with this object.

Forces this object to keep its buffers empty

If set to nonzero, forces a flush right away and after every write or print on the currently selected output channel. Default is 0 (regardless of whether the channel is really buffered by the system or not; $OUT_FH.autoflush tells you only whether you've asked Perl explicitly to flush after each write). $*OUT will typically be line buffered if output is to the terminal and block buffered otherwise. Setting this variable is useful primarily when you are outputting to a pipe or socket, such as when you are running a Perl program under rsh and want to see the output as it's happening. This has no effect on input buffering.

This role represents objects that depend on some external resource, which means that data might not be available at request.

    role IO::Streamable does IO {...}
    method new(
        Bool :$NoOpen,
        Bool :$Blocking,
        --> IO::Streamable
    ) {...}

Unless the NoOpen option is passed, an open will be done on the IO object when it is created.

If blocking is passed in, .blocking() is called (see below).

This allows the user to control whether this object should do a blocking wait or immediately return in the case of not having data available.

    method uri(Str $uri --> IO::Streamable) {...}

This should be callable on the class, and act like a kind of "new()" function. When given a URI, it returns an IO::Streamable of the appropriate type, and throws an error when an inappropriate type is passed in. For example, calling IO::File.uri('http://....') will throw an error (but will suggest using just uri('http://...') instead).

This is a generic role for encoded data streams.

Encoding and locale are required for sane conversions.

This role provides encoded access to a readable data stream, implies IO::Encoded. Might imply IO::Buffered, but that's not a requirement.

    method uri(Str $uri --> IO::Streamable);
    sub uri(Str $uri --> IO::Streamable);

Returns an appropriate IO::Streamable descendant, with the type depending on the uri passed in. Here are some example mappings:

    URI type IO type
    ======== =======
    file:    IO::File or IO::Directory
    ftp:     IO::Socket::INET (data channel)
    http:    IO::Socket::INET

These can naturally be overridden or added to by other modules.

For each protocol, stores a type name that should be instantiated by calling the uri constructor on that type, and passing in the appropriate uri.

Hey! The above document had some coding errors, which are explained below:

=back without =over

Something went wrong with that request. Please try again.