fio/handle
Types
An opaque, resource-safe file handle.
Always release with close/1 when done.
The internal platform handle (Erlang IoDevice or Node.js fd integer)
is invisible outside this module.
pub opaque type FileHandle
Mode used when opening a file handle.
pub type OpenMode {
ReadOnly
WriteOnly
AppendOnly
}
Constructors
-
ReadOnlyOpen for reading only. File must already exist.
-
WriteOnlyOpen for writing only. Creates the file or truncates it.
-
AppendOnlyOpen for appending only. Creates the file if absent.
Values
pub fn close(handle: FileHandle) -> Result(Nil, error.FioError)
Close a FileHandle, releasing the underlying OS file descriptor.
pub fn open(
path: String,
mode: OpenMode,
) -> Result(FileHandle, error.FioError)
Open a file and return a FileHandle.
Returns Error(FioError) if the file cannot be opened (e.g. Enoent,
Eacces). Use close to release the underlying OS file descriptor
when done.
pub fn read_all(
handle: FileHandle,
) -> Result(String, error.FioError)
Read all remaining content from the handle as a UTF-8 String.
Returns Error(NotUtf8("(handle)")) if the bytes are not valid UTF-8.
pub fn read_all_bits(
handle: FileHandle,
) -> Result(BitArray, error.FioError)
Read all remaining bytes from the handle into a BitArray.
Reads sequentially in 64 KiB chunks until EOF. Suitable for files of arbitrary size (only the final result is materialised in memory).
pub fn read_chunk(
handle: FileHandle,
size: Int,
) -> Result(option.Option(BitArray), error.FioError)
Read up to size bytes from the current cursor position of
the handle.
Ok(Some(data))— a chunk was read; cursor advances by|data|bytes.Ok(None)— end of file reached; cursor stays at the end.Error(FioError)— a read error occurred.
Use seek to move the cursor before calling read_chunk if you need
to read from a specific offset.
This is the primitive on which higher-level streaming can be built.
pub fn seek(
handle: FileHandle,
position: Int,
) -> Result(Nil, error.FioError)
Move the file cursor to position bytes from the start of the file.
After seek, the next read_chunk, read_all_bits, write, or
write_bits call will operate from the new offset.
// Re-read the first 10 bytes of a file
let assert Ok(h) = handle.open(path, handle.ReadOnly)
let assert Ok(_) = handle.seek(h, 0) // already at 0 after open
let assert Ok(a) = handle.read_chunk(h, 10)
let assert Ok(_) = handle.seek(h, 0) // back to start
let assert Ok(b) = handle.read_chunk(h, 10)
// a == b
Append mode note: in AppendOnly mode, seek moves the read cursor
(useful for mixed-use handles) but writes are always forced to end-of-file
by the OS regardless of cursor position. This is standard POSIX behaviour.
Passing an offset beyond the end of the file is allowed on most platforms (a subsequent write will create a sparse region).
pub fn tell(handle: FileHandle) -> Result(Int, error.FioError)
Return the current byte offset of the file cursor.
Useful to record a position before reading a block so you can return
to it later with seek.
let assert Ok(start) = handle.tell(h) // save position
let assert Ok(_) = handle.read_chunk(h, 64) // advance cursor
let assert Ok(_) = handle.seek(h, start) // restore position
pub fn with(
path: String,
mode: OpenMode,
callback: fn(FileHandle) -> Result(a, error.FioError),
) -> Result(a, error.FioError)
Open a file, run callback with the handle, then always close it.
This is the recommended way to use file handles. It is equivalent to
try-finally in other languages: the handle is closed even if callback
returns Error or if the Gleam runtime panics.
Designed for use with Gleam’s use syntax:
pub fn word_count(path: String) -> Result(Int, error.FioError) {
use h <- handle.with(path, handle.ReadOnly)
use text <- result.try(handle.read_all(h))
Ok(string.split(text, " ") |> list.length)
}
The return type of callback determines the return type of with.
The handle is always closed before with returns.
pub fn write(
handle: FileHandle,
content: String,
) -> Result(Nil, error.FioError)
Write a UTF-8 string to the handle at the current cursor position.
The cursor advances by the number of bytes written.
Use seek to write at a specific offset.
pub fn write_bits(
handle: FileHandle,
content: BitArray,
) -> Result(Nil, error.FioError)
Write raw bytes to the handle at the current cursor position.
The cursor advances by the number of bytes written.
Use seek to write at a specific offset.