# "Streams" _Path: en/lua/core/stream_ > "Stream read/write operations for handling data efficiently. Stream objects are obtained from other modules (HTTP, filesystem, etc.)." ## Table of Contents - Streams ## Content # Streams Streams provide incremental I/O for HTTP, filesystem, and other modules. The modules that own the underlying data create stream objects. This page is an API reference; the scanner loop uses an application-defined `process(token)` callback. ## Obtaining a Stream ```lua -- From HTTP request body local stream, err = req:stream() if err then return nil, err end -- From filesystem local fs = require("fs") local volume, err = fs.get("app:data") if err then return nil, err end local stream, err = volume:open("/file.txt", "r") if err then return nil, err end ``` ## Reading ```lua local chunk, err = stream:read(size) ``` | Parameter | Type | Description | |-----------|------|-------------| | `size` | integer | Bytes to read (0 = default 32KB chunk) | **Returns:** `string, error` — `nil, nil` on EOF ## Writing ```lua local bytes, err = stream:write(data) ``` | Parameter | Type | Description | |-----------|------|-------------| | `data` | string | Data to write | **Returns:** `integer, error` — bytes written ## Seeking ```lua local pos, err = stream:seek(whence, offset) ``` | Parameter | Type | Description | |-----------|------|-------------| | `whence` | string | `"set"`, `"cur"`, or `"end"` | | `offset` | integer | Offset in bytes | **Returns:** `integer, error` — new position ## Flushing ```lua local ok, err = stream:flush() ``` `flush` writes buffered data to the underlying destination. ## Stream Information ```lua local info, err = stream:stat() ``` | Field | Type | Description | |-------|------|-------------| | `size` | integer | Total size (-1 if unknown) | | `position` | integer | Current position | | `readable` | boolean | Can read | | `writable` | boolean | Can write | | `seekable` | boolean | Can seek | ## Closing ```lua local ok, err = stream:close() ``` `close` releases the stream's resources and can be called more than once. ## Scanner Create a scanner that tokenizes stream content: ```lua local scanner, err = stream:scanner(split) ``` | Parameter | Type | Description | |-----------|------|-------------| | `split` | string | `"lines"`, `"words"`, `"bytes"`, `"runes"` | ### Scanner Methods ```lua local has_more, err = scanner:scan() -- advance to next token local token = scanner:text() -- current token local err_msg = scanner:err() -- scanner error if any ``` ```lua while true do local has_token, err = scanner:scan() if err then return nil, err end if not has_token then local scan_err = scanner:err() if scan_err then return nil, scan_err end -- raw scanner error string break -- clean EOF end process(scanner:text()) end ``` When `scan()` returns `false`, check `scanner:err()` before treating the result as EOF. Tokenization and underlying read failures are stored on the scanner and do not appear in `scan()`'s second return value. ## Errors | Condition | Kind | |-----------|------| | Invalid whence/split type | raised as a Lua error (not returned) | | Stream closed | `INTERNAL` | | Not readable/writable | `INTERNAL` | | Read/write failure | `INTERNAL` | ## Navigation Previous: "Futures" (lua/core/future) Next: "Request Context" (lua/core/context)