Standardbibliothek
Antra::IO
import Antra::IOFile I/O for Antra.
slurp and spit intentionally return Result values instead of throwing directly.
They stay as the path-based convenience layer on top of Antra::IO::File.
Überblick#
Neben slurp(...) und spit(...) gibt es in Antra::IO jetzt auch kleine
Helper fuer die drei Standardstreams des aktuellen Prozesses:
IO.stdin()IO.stdout()IO.stderr()IO.pipe()
Sie liefern normale FileHandle-Werte und koennen deshalb direkt mit
print(...), println(...), File.read(...) oder File.write(...)
verwendet werden.
import Antra::IO as IO
my out = IO.stdout()
println("hello", [to: out])Die Rueckgabe sind dabei bewusst duplizierte Handles. Wenn du so einen Handle
mit File.close(...) schliesst, bleibt der globale Prozess-Stream selbst
trotzdem benutzbar.
IO.pipe() erzeugt dagegen ein frisches anonymes Reader/Writer-Paar fuer
niedrigstufige Stream-Verkabelung:
import Antra::IO as IO
import Antra::IO::File as File
import Antra::Result as Result
my [reader, writer] = IO.pipe().!
Result.unwrap!(File.write(writer, "hello"))
Result.unwrap!(File.close(writer))
println(File.read_all(reader).!)
Result.unwrap!(File.close(reader))Referenz#
IO.slurp(path)
IO.slurp(path, [encoding: "UTF-8"])
IO.spit(path, content)
IO.spit(path, content, [append: true])
IO.spit(path, content, [append: true, encoding: "UTF-8"])
IO.prompt(prompt)
IO.prompt(prompt).!
IO.prompt_required(prompt)
IO.prompt_required(prompt).!
IO.pipe()
IO.pipe().!Fuer handle-basiertes Lesen und Schreiben gibt es zusaetzlich Antra::IO::File:
File.open(path)
File.open(path, [mode: [:read], binary: false, encoding: "UTF-8"])
File.open(path).!
File.read(handle, n)
File.read_all(handle)
File.read_byte(handle)
File.read_byte(handle).!
File.read_char(handle)
File.read_char(handle).!
File.read_line(handle)
File.read_line(handle).!
File.write(handle, data)
File.flush(handle)
File.seek(handle, offset)
File.seek(handle, offset, [from: :start])
File.position(handle)
File.close(handle)
File.with_open(path, |fh| -> ...)
File.with_open(path, [binary: true], |fh| -> ...)
File.with_open!(path, |fh| -> ...)open, with_open und with_open! nennen ihre Optionen in der Signatur statt
ein undurchsichtiges Array zu nehmen. Drei gibt es: mode: (Flags :read,
:write, :append, :create, :truncate als Array oder einzeln, dazu die
Kurz-Aliase "<", ">", ">>", "<+", "+>"), binary: und encoding:.
Das Array darf ganz entfallen — auch wenn ein Callback dahinter steht. Ein
falsch geschriebener Name ist deshalb kein still ignorierter Key mehr, sondern
ein Fehler, der die erlaubten nennt:
Error: No matching clause for File.open with 2 args: notes.txt, [binry: true]
Hint: Unknown key(s) in keyword-array argument 2: binry. Accepted: mode, binary, encoding.File.read_line(...) liest genau eine Textzeile vom aktuellen Handle-Offset,
entfernt ein abschliessendes \n oder \r\n und liefert %Ok[%Some[line]]
fuer gelesene Zeilen sowie %Ok[%None[]] an EOF statt eines Fehlers.
File.read_byte(...) ist die binaere Schwester dazu: genau ein Byte lesen,
%Ok[%Some[0..255]] bei Erfolg und %Ok[%None[]] an EOF. Umgekehrt liest
File.read_char(...) genau ein decodiertes Zeichen von einem Text-Handle und
liefert ebenfalls %Ok[%Some[...]] oder %Ok[%None[]].
Diese drei sind an einen Modus gebunden, und der falsche ist ein Fehler, kein stiller Fallback:
| Funktion | Text-Handle | binary: true |
|---|---|---|
read / read_all | %Ok[String] | %Ok[ByteString] |
read_line | %Ok[%Some[line]] | Fehler |
read_char | %Ok[%Some[char]] | Fehler |
read_byte | Fehler | %Ok[%Some[0..255]] |
read_line und read_char dekodieren nach encoding: — im Binaermodus gibt es
nichts zu dekodieren, und was eine „Zeile" aus Bytes waere (Trennzeichen? \r
mitzaehlen?) beantwortet die Funktion bewusst nicht selbst. Wer Bytes will,
nimmt read/read_all oder read_byte.
Fuer einfache interaktive CLI-Eingabe gibt es zusaetzlich IO.prompt(...).
Die Funktion schreibt den Prompt ohne automatischen Zeilenumbruch nach stdout
und liest danach genau eine Zeile von stdin als
%Ok[%Some[line]] | %Ok[%None[]] | %Err[%Error{...}].
Wenn fehlende Eingabe fachlich nicht normal, sondern exceptional ist, gibt es
zusaetzlich IO.prompt_required(...). Diese Schwester hebt EOF in einen
%Err[%Error{...}]-Fall an und passt damit besser zu linearen use-Flows.
Funktionen#
pipepromptprompt_requiredread_keyread_line_cancelableread_line_hiddenread_line_maskedselectselect!slurpspitstderrstdinstdin_is_ttystdoutwith_raw_stdin
fn pipe()Creates an anonymous pipe as [reader, writer].
The returned handles are normal FileHandle values and can be used with
Antra::IO::File or passed into fork/process helpers.
Example:
Result.run {
val [reader, writer] = IO.pipe().^
File.write(writer, "hello").^
File.close(writer).^
println(File.read_all(reader).^)
File.close(reader).^
}fn prompt(prompt_text)Writes prompt to stdout and reads one line from stdin.
Returns %Ok[%Some[line]], %Ok[%None[]] at EOF, or %Err[%Error{...}].
fn prompt_required(prompt_text)Writes prompt to stdout and requires one input line from stdin.
Returns %Ok[line] on success or %Err[%Error{...}] on EOF or I/O error.
fn read_key()Reads one logical key from stdin.
Returns %Ok[%Some[key]], %Ok[%None[]] at EOF, or %Err[%Error{...}].
fn read_line_cancelable()Reads one line from stdin, turning a Ctrl-C (SIGINT) during the read into a cancellation instead of killing the process.
Line editing works as usual (canonical mode). Returns %Ok[%Some[line]],
%Ok[%None[]] at EOF, or %Err[%Error{kind: :cancelled}] on Ctrl-C. On a
non-TTY stdin it degrades to a normal line read.
fn read_line_masked(mask)Reads one line from stdin echoing mask (e.g. "*") for each character
instead of the real input, with visible Backspace/Delete editing.
Line editing works on a per-character basis; only the mask is shown. On a
non-TTY stdin it degrades to a normal line read. Returns %Ok[%Some[line]],
%Ok[%None[]] at EOF, or %Err[%Error{kind: :cancelled}] on Ctrl-C.
fn select(opts)Waits until at least one of the given handles is ready to be read.
Accepts FileHandle and Socket values in one call — pipes, standard
streams, open files, connected sockets and listeners. Returns readiness
only, never data: use File.read(...) or Socket.recv(...) afterwards.
EOF counts as readable, which is how a closed peer is detected.
timeout_ms: is undef to block until a handle is ready, 0 for an
immediate snapshot, or a positive number of milliseconds. A timeout
without an event is not an error and yields %{read: []}.
Returns %Ok[%{read: [handle, ...]}] in input order, or %Err[%Error{...}].
Example:
my ready = IO.select([read: [stdout, stderr], timeout_ms: 100]).^
if (Enum.member?(ready.read, stdout)) {
println(File.read(stdout, 1024).^)
}fn select!(opts)fn slurp(path)
fn slurp(path, [encoding: = "UTF-8", ..])Reads a file as a string.
Returns %Ok["..."] or %Err[%Error{...}].
Example:
val raw = IO.slurp("examples/people.csv").^
val legacy = IO.slurp("legacy.txt", [encoding: "ISO-8859-1"]).^fn spit(path, content)
fn spit(path, content, [append: = false, encoding: = "UTF-8", ..])Writes a string to a file.
Returns %Ok[undef] or %Err[%Error{...}].
Example:
IO.spit("out.txt", "hello").^
IO.spit("out.txt", " world", [append: true]).^
IO.spit("legacy.txt", "hallo", [encoding: "ISO-8859-1"]).^fn stderr()Returns a writable handle for the current process STDERR.
fn stdin()Returns a readable handle for the current process STDIN.
fn stdin_is_tty()Returns true when the current stdin is attached to a TTY.
fn stdout()Returns a writable handle for the current process STDOUT.
fn with_raw_stdin(f)Enables raw stdin for the dynamic scope of f and restores the previous
terminal state afterwards.
