Antra

Standardbibliothek

Antra::IO::File

import Antra::IO::File

Handle-based file I/O for Antra.

This module provides a small file-handle API on top of Antra::Native::IO::File.

The API is split into two layers:

  • low-level handle operations such as open, read, write, seek, and close
  • scoped helpers such as with_open that manage handle lifetime for a callback

open, with_open and with_open! name their options in the signature (mode:, binary:, encoding:) instead of taking an opaque array. Two things follow from that, and both are deliberate:

  • The option array may be left out entirely - a final keyword-array parameter stays implicit even with a callback behind it. That is why there is one clause per function rather than one with options and one without.
  • A misspelled option is a clause mismatch, not a silently ignored key. The error names the accepted keys, so it also covers the access flags removed on 30.06.2026 ([write: true] points at mode:). It throws rather than returning %Err[...]: a wrong option name is a mistake in the program, not a condition of the run like a missing file.

The non-bang functions return %Ok[...] or %Err[...] where appropriate. Bang variants are kept where they unwrap into a meaningful value such as a handle, string, bytes, or position. Pure effect operations like close(...) and write(...) stay in the explicit Result channel.

Funktionen#

fn close(handle)

Closes a file handle.

Returns %Ok[undef] on success or %Err[%Error{...}].

Example:

val %Ok[_] = File.close(fh)
fn flush(handle)

Flushes any buffered output on a handle to the underlying device.

Returns %Ok[undef] or %Err[%Error{...}].

fn open(path, [
        mode: = [:read],
        binary: = false,
        encoding: = "UTF-8"
    ])

Opens a file, for reading as UTF-8 text unless told otherwise.

Returns %Ok[#FileHandle<...>] or %Err[%Error{...}].

The options are named in the signature instead of being passed through as an opaque array. That is what lets an editor offer them, and it is why a misspelled option is reported - as a clause mismatch naming the accepted keys - rather than silently ignored.

mode: takes the flags the file is opened with:

  • :read - open for reading
  • :write - open for writing
  • :append - every write goes to the end; excludes :truncate
  • :create - create the file if it does not exist
  • :truncate - empty an existing file

At least one of :read, :write or :append must be present. A single flag may be written without the array (mode: :read).

Five string aliases stand for the usual combinations:

aliasflags
"<"[:read]
">"[:write, :create, :truncate]
">>"[:append, :create]
"<+"[:read, :write]
"+>"[:read, :write, :create, :truncate]

binary: opens the handle without character decoding, encoding: names the codec for text mode. Both are ignored by the other one.

Example:

val %Ok[fh] = File.open("notes.txt")
val %Ok[out] = File.open("out.txt", [mode: [:write, :create, :truncate]])
val %Ok[log] = File.open("app.log", [mode: ">>"])
val %Ok[raw] = File.open("blob.bin", [mode: "<", binary: true])
fn position(handle)

Returns the current file position.

Returns %Ok[position] or %Err[%Error{...}].

Example:

val %Ok[pos] = File.position(fh)
fn read(handle, n)

Reads up to n bytes from a file handle.

Returns %Ok[String] in text mode or %Ok[ByteString] in binary mode. Read failures are returned as %Err[%Error{...}].

Works in both modes - unlike read_line/read_char, which are text only, and read_byte, which is binary only.

Example:

val %Ok[chunk] = File.read(fh, 5)
fn read_all(handle)

Reads from the current position to the end of the file.

Returns %Ok[String] in text mode or %Ok[ByteString] in binary mode. Read failures are returned as %Err[%Error{...}].

Example:

val %Ok[rest] = File.read_all(fh)
fn read_byte(handle)

Reads a single raw byte from a binary file handle.

Returns %Ok[%Some[byte]] for a byte value in 0..255, %Ok[%None[]] at EOF, or %Err[%Error{...}].

Binary only, mirroring read_char: on a text handle this is an error.

Example:

val %Ok[byte] = File.read_byte(fh)
fn read_char(handle)

Reads a single decoded character from a text file handle.

Returns %Ok[%Some[char]] for one character, %Ok[%None[]] at EOF, or %Err[%Error{...}].

Text only, mirroring read_byte: on a binary handle this is an error.

Example:

val %Ok[char] = File.read_char(fh)
fn read_line(handle)

Reads a single text line from the current position.

Returns %Ok[%Some[line]] for a line, %Ok[%None[]] at EOF, or %Err[%Error{...}]. The line itself does not include a trailing \n or \r\n.

Text only: on a binary: true handle this is an error, not a ByteString. A "line" of bytes would have to answer what it splits on and whether \r counts, and rather than decide that silently the function refuses. Read bytes with read/read_all, which work in both modes, or byte by byte with read_byte.

Example:

val %Ok[line] = File.read_line(fh)
fn seek(handle, offset)
fn seek(handle, offset, [from: = :start])

Seeks to an absolute offset from the start of the file.

Returns %Ok[position] for the new offset or %Err[%Error{...}].

Example:

val %Ok[pos] = File.seek(fh, 0)
fn with_open(path, [
        mode: = [:read],
        binary: = false,
        encoding: = "UTF-8",
    ], f)

Opens a file, passes the handle to f, and closes it again afterwards.

This is the Result-oriented variant intended for use and propagation-friendly composition. The callback should return %Ok[...] or %Err[...], and that Result is passed through without adding an extra wrapper.

with_open is responsible for resource lifetime, not for implicitly chaining every fallible handle operation inside the callback. Inside the callback you normally continue explicitly in the Result channel, e.g. with File.read(...) ? or Result.and_then(...) where that reads clearer.

mode:, binary: and encoding: are the ones open takes and mean the same here - see there for the flags and the string aliases. They may be omitted entirely; a final keyword-array parameter stays implicit even with a callback behind it.

Example:

fn preview(path) -> {
    use fh <- File.with_open(path)
    File.read(fh, 5)
}
fn with_open!(path, [
        mode: = [:read],
        binary: = false,
        encoding: = "UTF-8",
    ], f)

Opens a file, runs f, closes the handle, and returns the raw callback result.

This is the bang/raw counterpart for callbacks that work with throwing operations such as File.read(fh, n).!.

Use this variant when the callback already follows bang-style control flow and you do not want to stay in the explicit Result channel.

Takes the same options as open; see there.

fn write(handle, data)

Writes text or binary data to a file handle.

Returns %Ok[undef] on success or %Err[%Error{...}]. Like close, it is a pure effect and stays in the Result channel - there is no bang variant, because unwrapping it would yield nothing worth having.

Example:

val %Ok[_] = File.write(fh, "hello")

Quelle dieser Seite