Working with Streams

The stream API moves binary data and decoded Unicode text through a uniform set of bounded operations. It gives files, standard I/O, temporary files, memory-backed output, and custom data sources the same vocabulary. Every public operation has a configured time bound, reads distinguish data from timeout and normal completion, and writes accept a complete request or none of it.

The following sections map the complete API by task. Use them to identify the part you need, then follow the linked topic for the detailed contracts and executable examples.

Creating Streams and Managing Ownership

Start here when you need to choose a stream type, open a file, configure it, or decide how a component should receive a stream. The four central interfaces separate raw bytes from decoded text and input from output:

Data

Read

Write

Exact binary representation

ByteInputStream

ByteOutputStream

Decoded Unicode text

TextInputStream

TextOutputStream

File streams are opened through Path::content() and returned with shared ownership. Read Creating Streams and Managing Ownership for the opening methods, path and stream settings, explicit cleanup, and best practices for passing the narrowest useful interface.

Byte Input and Output

Use byte streams for file formats, network frames, checksums, compressed content, or any operation where every byte is significant. They support bounded reads into spans, retained exact reads, explicitly limited aggregate reads, atomic writes, and endian-aware integer operations.

If you are deciding how to handle a short read, resume after a timeout, cap memory use, or retry a write without duplicating data, continue with Byte Input and Output.

Text Input, Output, and Encoding

Text streams place the encoding boundary below your application logic. They decode complete Unicode code points, read lines and bounded text blocks, write strings and formatted values, and can capture generic text output in memory.

Use this API for configuration files, reports, logs, or any data whose meaning is text rather than bytes. Read Text Input, Output, and Encoding for line semantics, UTF-8/16/32, byte order and BOM handling, encoding errors, and the difference between configured and effective encoding.

Standard Streams

Standard input, output, and error connect a command-line application to its surrounding process. The API provides stable stdIn(), stdOut(), and stdErr() proxies plus concise io formatting helpers.

Use these streams for interactive input, normal program output, diagnostics, and tests that temporarily capture or provide process I/O. Read Standard Streams before redirecting them: redirects are scoped but process-wide, and standard proxies have different ownership rules from ordinary files.

Readiness and Timeouts

Bounded operations let an application remain responsive when a source is slow or a destination cannot immediately accept work. A timeout is a normal result, not end-of-stream and not a failed stream; readiness checks help decide whether retrying can make progress.

Use this part of the API for pipes, terminals, concurrent producers, event-style loops, and any workflow that must periodically regain control. Read Readiness and Timeouts for complete input and output retry loops and the exact roles of isReady() and waitForReady().

Buffering and Back Pressure

Buffering smooths the difference between the size and timing of application requests and native I/O. For output, accepted data may still be queued; back pressure prevents an application from growing that queue without a limit.

Configure this area when moving large data, choosing bounded chunk sizes, controlling memory use, or coordinating multiple producers. Read Buffering and Back Pressure to understand front and back buffers, oversized requests, readiness, and when a successful flush() matters.

Stream Lifecycle

Streams move through Open, Closing, Closed, and Failed states. Writes, flushing, graceful close, immediate abort, and destruction each make a different guarantee about queued work.

You need these contracts whenever output must not be lost, shutdown can time out, or a stored native failure must be reported reliably. Read Stream Lifecycle for close loops, failure propagation, abort behavior, and deterministic resource release.

Temporary Streams

Temporary streams create a uniquely named byte or text file and combine its stream with an explicit cleanup policy. They are useful for staging an export, materializing intermediate data for another tool, or producing a file that should disappear unless ownership is deliberately transferred.

Read Temporary Streams to configure location, names, access, encoding, and removal; retrieve the path; use release(); and understand cleanup after close, abort, destruction, or failure.

Positioning Streams

Positioning provides random access to streams whose backing target can support it. Positions are logical encoded-byte offsets, so buffered read-ahead and queued writes do not change the position visible to the caller.

Use positioning for fixed-size records, trailers, indexes, sparse output, or carefully designed random access in encoded text. Read Positioning Streams before seeking: not every stream supports it, append output is excluded, and text boundaries, BOMs, retained input, and timeout behavior require deliberate handling.

Stream Errors and Diagnostics

The API keeps timeout, normal end-of-stream, encoding failure, and stream failure separate so recovery code does not confuse ordinary flow control with broken I/O. When a stream does fail, StreamError carries a structured diagnostic with operation, path, help, and native platform context.

Use Stream Errors and Diagnostics when designing logging, user-facing reports, recovery boundaries, or wrapped streams that must preserve the original source context.

Coroutine Streams

Coroutine operations execute blocking stream work through the worker service without changing the familiar read and write result states. Eager CoTask objects handle one operation, while lazy generators yield successive blocks or lines, including timeout results.

Use them when a coroutine-based component must await I/O or consume a stream incrementally without occupying the caller thread. Read Coroutine Streams for shared ownership across suspension, generator completion, cancellation by destruction, single-consumer rules, and continuation-thread expectations.

Writing Custom Streams

Custom streams connect the common API to an application-specific source or target: an archive entry, protocol channel, device, generated data set, or test double. The base classes supply higher-level behavior only when the implementation obeys the bounded-read, atomic-write, lifecycle, readiness, failure, and optional-positioning contracts.

Use Writing Custom Streams when no built-in stream represents your boundary. It develops complete custom byte input and output streams, explains error context and coroutine ownership, and finishes with a contract-testing checklist.