6.54. kink/io/FILE

Operates files in the filesystem.

6.54.1. FILE.open_to_read(Path ...[$config={}])

`open_to_read` opens the file specified by `Path` as a byte input stream. The result supports `input` type.

Config methods:

• C.no_buffer / C.buffer(Max_buf_size)

• C.on_success($success): default = VAL.identity

• C.on_error($error): default = a fun which raises an exception

When the file is opened, `open_to_read` tail-calls $success with an `input`.

If an IO error occurs, `open_to_read` tail-calls $error with an `exception`.

Buffering

The result `input` performs userspace buffering by default.

To limit the buffer size, call C.buffer. The byte length of the buffer does not exceed `Max_buf_size`.

To disable userspace buffering, call C.no_buffer.

Preconditions

`Path` must be a `str`.

`Max_buf_size` must be a positive int `num`.

$success must be a fun which takes an `input`.

$error must be a fun which takes an `exception`.

Example

:FILE.require_from('kink/io/')
:CONTROL.require_from('kink/')

CONTROL.with_finally{(:finally)
  :In = FILE.open_to_read('/dev/urandom')
  finally{ In.close }
  :Bin = In.read(10)
  stdout.print_line(Bin.repr)
}
# Output differs each time:
#   (bin 0xbe 0x62 0xe8 0x75 0xd4 0x88 0xd4 0xfc 0xc4 0x31)

:Result <- FILE.open_to_read('/no/such/file'){(:O)
  O.on_error{(:Exc) 'error: {}'.format(Exc.message) }
}
stdout.print_line(Result.repr)
# => "error: cannot open to read: \"/no/such/file\""

6.54.2. FILE.open_to_scan(Path Charset ...[$config={}])

`open_to_scan` opens the file specified by `Path` as a character input stream. The result supports both `scanner` and `input` types.

Config methods:

• C.no_buffer / C.buffer(Max_buf_size)

• C.replace_conversion_error

• C.on_success($success): default = VAL.identity

• C.on_error($error): default = a fun which raises an exception

If the file is opened, `open_to_scan` tail-calls $success with the scanner+input.

If an IO error occurs, `open_to_scan` tail-calls $error with an `exception`.

Buffering

The result scanner+input performs userspace buffering by default.

To limit the buffer size, call C.buffer. The byte length of the buffer does not exceed `Max_buf_size`.

To disable userspace buffering, call C.no_buffer.

String decoding

`Charset` is used to decode bytes into strings.

When `scan_line` or `scan` methods detect malformed byte sequence or a character which cannot be mapped to Unicode, an IO error occurs by default.

If C.replace_conversion_error is called, `scan` and `scan_line` insert replacement character sequence into the string instead of an IO error.

Preconditions

`Path` must be a `str`.

`Charset` must be a `charset`.

`Max_buf_size` must be a positive int num.

$success must be a fun which takes a scanner+input

$error must be a fun which takes an `exception`

6.54.3. FILE.open_to_write(Path ...[$config={}])

`open_to_write` opens the file specified by `Path` as a byte output stream. The result supports `output` type.

Config methods:

• C.append

• C.no_buffer / C.buffer(Max_buf_size)

• C.on_success($success): default = VAL.identity

• C.on_error($error): default = a fun which raises an exception

If the file is successfully opened, `open_to_write` tail-calls $success with an `output`.

If an IO error occurs, `open_to_write` tail-calls $error with an `exception`.

Truncation and creation

If the specified file exists, by default, `open_to_write` truncates the file to length 0.

If the specified file exists, and C.append is called, `open_to_write` opens the file without truncating the content. The file pointer is set at the end of the file.

If the specified file does not exist, `open_to_write` makes a new empty file.

Buffering

The result `output` performs userspace buffering by default.

To limit the buffer size, call C.buffer. The byte length of the buffer does not exceed `Max_buf_size`.

To disable userspace buffering, call C.no_buffer.

Preconditions

`Path` must be a `str`.

`Max_buf_size` must be a positive int `num`.

$success must be a fun which takes an `output`.

$error must be a fun which takes an `exception`.

Example

:FILE.require_from('kink/io/')
:CONTROL.require_from('kink/')
:CHARSET.require_from('kink/')

CONTROL.with_finally{(:finally)
  :Out = FILE.open_to_write('/dev/stdout')
  finally{ Out.close }
  Out.write(CHARSET.ascii.str_to_bin("hello\n"))
}
# => hello

6.54.4. FILE.open_to_print(Path Charset Newline ...[$config={}])

`open_to_print` opens the file specified by `Path` as a character output stream. The result supports both `printer` and `output` types.

Config methods:

• C.append

• C.no_buffer / C.buffer(Max_buf_size)

• C.flush_on_print

• C.replace_conversion_error

• C.synchronize

• C.on_success($success): default = VAL.identity

• C.on_error($error): default = a fun which raises an exception

If a file is successfully open, `open_to_print` tail-calls $success with a printer+output.

If an IO error occurs, `open_to_print` tail-calls $error with an `exception`.

`Newline` will be used by `printe_line` method as the line separator.

Truncation and creation

If the specified file exists, by default, `open_to_print` truncates the file to length 0.

If the specified file exists, and C.append is called, `open_to_print` opens the file without truncating the content. The file pointer is set at the end of the file.

If the specified file does not exist, `open_to_print` makes a new empty file.

Buffering

The printer+output performs userspace buffering by default.

To limit the buffer size, call C.buffer. The byte length of the buffer does not exceed `Max_buf_size`.

To disable userspace buffering, call C.no_buffer.

If C.flush_on_print is called, and the printer+output is bufferred, the printer+output flushes the buffer after each invocation of `print` and `print_line`.

String encoding

`Charset` will be used to encode strings to bytes.

When a string cannot be encoded, by default, an IO error occurs.

If C.replace_conversion_error is called, `print` and `print_line` methods write replacement byte sequence instead of an IO error.

Synchronization

If C.synchronize is called, `write`, `flush`, `print`, `print_line`, and `close` methods are serialized by a single mutex.

Preconditions

`Path` must be a `str`.

`Charset` must be a `charset`.

`Newline` must be a `str`.

`Max_buf_size` must be a positive int `num`.

$success must be a fun which takes a printer+output.

$error must be a fun which takes an `exception`.

6.54.5. FILE.mkdir(Path ...[$config={}])

`mkdir` makes a directory named `Path`.

Config methods:

• C.on_success($success): default = {}

• C.on_error($error): default = a fun which raises an exception

If a directory is successfully made, `mkdir` tail-calls $success with no arg.

If an IO error occurs, `mkdir` tail-calls $error with an `exception`.

Preconditions

`Path` must be a `str`.

$success must be a fun which takes no arg.

$error must be a fun which takes an `exception`.

6.54.6. FILE.rm(Path ...[$config={}])

`rm` removes an filesystem entry named `Path`.

Config methods:

• C.on_success($success): default = {}

• C.on_error($error): default = a fun which raises an exception

If the filesystem entry is successfully removed, `rm` tail-calls $success with no arg.

If an IO error occurs, `rm` tail-calls $error with an `exception`.

Preconditions

`Path` must be a str.

$success must be a fun which takes no arg.

$error must be a fun which takes an `exception`.

6.54.7. FILE.ls(Dir_path ...[$config={}])

`ls` fetches the entries directly under the directory specified by `Dir_path`. The paths of the entries will have the parts of `Dir_path` as the leading parts. `ls` returns a `vec` of the paths of the entries.

Config methods:

• C.on_success($success): default = VAL.identity

• C.on_error($error): default = a fun which raises an exception

If entries are fetched successfully, `ls` tail-calls $success with a `vec` of the paths.

If an IO error occurs, `ls` tail-calls $error with an `exception`.

Preconditions

`Dir_path` must be a str.

$success must be a fun which takes a `vec`.

$error must be a fun which takes an `exception`.

Example

:FILE.require_from('kink/io/')

stdout.print_line(FILE.ls('/home').repr) # => ["/home/jake" "/home/elwood"]
stdout.print_line(FILE.ls('bin').repr)   # => ["bin/kinkw.exe" "bin/kink.exe" "bin/kink"]

6.54.10. FILE.realpath(Path ...[$config={}])

`realpath` fetches the absolute real path of `Path`, resolving symlinks, hardlinks like '..', duplicated path separators, and so on.

Config methods:

• C.on_success($success): default = VAL.identity

• C.on_error($error): default = a fun which raises an exception

If the real path is successfully read, `realpath` tail-calls $success with a `str` of the real path.

If an IO error occurs, `realpath` tail-calls $error with an `exception`.

Preconditions

`Path` must be a `str`.

$success must be a fun which takes a `str` of the real path.

$error must be a fun which takes an `exception`.

Example

:FILE.require_from('kink/io/')

stdout.print_line(FILE.realpath('/usr/local/bin/..')) # => /usr/local

6.54.11. FILE.basename(Path)

`basename` returns the name of the filesystem entry at the last part of `Path`.

If `Path` does not contain such an entry, `basename` returns an empty `str`.

Precondition

`Path` must be a `str`.

Examples

On a Unix like system:

:FILE.require_from('kink/io/')

:base <- {(:Path)
  :Base = FILE.basename(Path)
  stdout.print_line(Base)
}
base('bin/kink') # => kink
base('/home') # => home
base('/') # =>

On Windows:

:FILE.require_from('kink/io/')

:base <- {(:Path)
  :Base = FILE.basename(Path)
  stdout.print_line(Base)
}
base('bin/kink.exe')  # => kink.exe
base('bin\kink.exe')  # => kink.exe
base('C:\Users')  # => Users
base('C:/Users')  # => Users
base('C:foo')  # => foo
base('C:\')    # =>
base('C:/')    # =>
base('C:')     # =>

6.54.12. FILE.dirname(Path)

`dirname` returns the path excluding the name of the filesystem entry of the last part of `Path`.

If `Path` does not contain such an filesystem entry, `dirname` returns the path which is semantically equivalent to `Path`.

Precondition

`Path` must be a `str`.

Examples

On a Unix like system:

:FILE.require_from('kink/io/')

:dir <- {(:Path)
  :Dir = FILE.dirname(Path)
  stdout.print_line(Dir)
}
dir('bin/kink') # => bin
dir('/home') # => /
dir('/') # => /

On Windows:

:FILE.require_from('kink/io/')

:dir <- {(:Path)
  :Dir = FILE.dirname(Path)
  stdout.print_line(Dir)
}
dir('bin/kink.exe')  # => bin
dir('bin\kink.exe')  # => bin
dir('C:\Users')  # => C:\
dir('C:/Users')  # => C:\
dir('C:foo')  # => C:
dir('C:\')    # => C:\
dir('C:/')    # => C:\
dir('C:')     # => C:

6.54.13. FILE.pwd

`pwd` returns the absolute path of the current directory.

6.54.14. FILE.separator

`separator` returns the path separator of the host system.

The result is either "/" or "\".

6.54.15. FILE.file?(Path)

`file?` returns whether the current process can determine the filesystem entry named `Path` is a regular file.

6.54.16. FILE.dir?(Path)

`dir?` returns whether the current process can determine the filesystem entry named `Path` is a directory.

6.54.18. FILE.present?(Path)

`present?` returns whether the current process can determine the filesystem entry named `Path` exists.