Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Stream Types

This page is the shared API for text and byte streams. TextRead / TextWrite / ByteRead / ByteWrite are the roles; TextReader, TextWriter, ByteReader, and ByteWriter are the usual concrete handles (factories below). Backing-specific openers (file path, in-memory string, ByteList) are illustrated in the following pages; the read / write / close / flush members are the same regardless of how you opened the stream.

Common patterns

Opening: bare vs ?

File-backed factories come in two forms (same convention as casts and File.readBytes / readBytes?):

  • bare — must succeed; panics on open failure (( path:s -- stream ))
  • ? — modal result for caller-handled failure

Modal shape (same as Writing Clean Final Code):

  • success: ( … -- stream true )
  • failure: ( … -- err:String false )
"notes.txt" TextReader.newFromFile?^ not if
  $ nl                    // err string
else
  >ts
  // … use t: …
  t:.close^
  t:drop
then

When open must succeed (system / mandatory path):

"notes.txt" TextReader.newFromFile^ >ts

Reading: value plus OK

Text and byte next / line reads use the Final modal apishape:

FamilyEffect
Text( -- rune:i true | false ) or ( -- line:s true | false )
Byte( -- b:i true | false )

true means you got a value; false means end of stream (no placeholder value). Chunked readBytes is different: it returns a ByteList (possibly empty) and does not use a flag — empty means no more data (or a non-positive count).

Writing, flush, and close

  • Writers buffer; call flush when you need data to reach the backing store before close.
  • close releases the backing handle when the provider supports it (files do; many in-memory providers are no-ops). Safe to call when you are done.
  • Put the stream on ts (or another aux stack) for a short session of method calls, then t:drop — same style as other objects (Writing Clean Final Code).

Iteration

TextReader is iterable. Put the reader on DS and use foreach … /foreach; i is each Unicode code point as Int. The loop consumes the reader (see foreach).


TextReader

Read Utf-8 text as runes or lines. A TextRead (getNextRune); readLine is on this concrete type.

Factories (class)

NameEffectDescription
newFromFile( path:s -- r )open path; panics on error
newFromFile?( path:s -- r true | err:s false )open path for sequential text read
newFromString( s:String -- r true | err:s false )read over an in-memory String

Instance methods

NameEffectDescription
getNextRune( -- r:i true | false )next Unicode code point
readLine( -- line:s true | false )next line without the newline; strips a trailing \r
close( -- )release the reader
"hi" TextReader.newFromString^ drop >ts
t:.getNextRune^ if
  r>s $               // prints h
then
t:.close^
t:drop

TextWriter

Write Utf-8 text (runes, strings, or lines). A TextWrite.

Factories (class)

NameEffectDescription
newFromFileAppendOrCreate( path:s -- w )append; create if missing; panics
newFromFileAppendOrCreate?( path:s -- w true | err:s false )append; create if missing
newFromFileTruncateOrCreate( path:s -- w )truncate or create; panics
newFromFileTruncateOrCreate?( path:s -- w true | err:s false )truncate or create

StringBuilder is a TextWrite: call its writeRune / writeString / writeLine members (same shape as below), then take .toString^. See String Streams.

Instance methods

NameEffectDescription
writeRune( r:i -- )write one Unicode code point
writeString( s:String -- )write as-is (no added newline)
writeLine( s:String -- )write string then \n
flush( -- )push buffered output
close( -- )flush/release as needed
"out.txt" TextWriter.newFromFileTruncateOrCreate^ >ts
"hello" t:.writeLine^
t:.flush^
t:.close^
t:drop

ByteReader

Read raw bytes. A ByteRead. Values on DS are Int (0…255) for a single byte, or a ByteList for a chunk.

Factories (class)

NameEffectDescription
newFromFile( path:s -- r )open path; panics on error
newFromFile?( path:s -- r true | err:s false )open path for sequential byte read
newFromBytes( bytes:ByteList -- r true | err:s false )read over an existing buffer

Instance methods

NameEffectDescription
getNextByte( -- b:i true | false )next octet
readBytes( n:i -- bytes:ByteList )up to n bytes (may be shorter / empty)
close( -- )release the reader
ByteList.new^ >xs
65 x:.append^
66 x:.append^
x:peek ByteReader.newFromBytes^ drop >ts
t:.getNextByte^ if
  $                       // 65
then
t:.close^
t:drop
x:drop

ByteWriter

Write raw bytes into a file or append into a ByteList. A ByteWrite.

Factories (class)

NameEffectDescription
newFromFileAppendOrCreate( path:s -- w )append; create if missing; panics
newFromFileAppendOrCreate?( path:s -- w true | err:s false )append; create if missing
newFromFileTruncateOrCreate( path:s -- w )truncate or create; panics
newFromFileTruncateOrCreate?( path:s -- w true | err:s false )truncate or create
newFromBytes( bytes:ByteList -- w true | err:s false )append writes into that list

Instance methods

NameEffectDescription
writeNextByte( b:iu -- )write one octet (Int or Uint)
writeBytes( bytes:ByteList -- )write all bytes from the list
flush( -- )push buffered output
close( -- )flush/release as needed
ByteList.new^ >xs
x:peek ByteWriter.newFromBytes^ drop >ts
65 t:.writeNextByte^
ByteList.new^ >ys
66 y:.append^
67 y:.append^
y:peek t:.writeBytes^
y:drop
t:.flush^
t:.close^
t:drop
x:.len@ $ nl          // 3
x:drop