Standard Library & Runtime

Files & Resources

Read and write files, handle errors with Result, and close an open File with using or defer.

Read or write a whole file with FS, or keep a File open for several operations. Handle failures with Result and choose when the file closes with using or defer.

Install Topaz through First Program. The environment running your program must allow filesystem access. Importing a module does not grant that permission.

Read through one managed File

In a working folder, create a UTF-8 file named note.txt containing ready. Save this program beside it as files-resources.tpz.

TOPAZ
function readNote(path: string) -> Result<string, string> {
    let mut result: Result<string, string> = Err("not read")
    using file = open(path)? {
        result = file.read()
    }
    return result
}

match readNote("note.txt") {
    case Ok(text) => print(text.trim())
    case Err(error) => print(error)
}

Run topaz run files-resources.tpz from that folder.

Output
ready

open returns Ok(file) when the file opens. If opening fails, ? returns the error from readNote before entering the block.

After opening, using binds file and registers its close call. file.read() stores its Result in the outer variable. Leaving the block closes the file, then the function returns the stored result.

If note.txt is missing, the program prints the error from open. Restore the file in the working folder and run again. The Err branch prints an error string, so this program can exit successfully even when reading fails.

Choose FS or File

TaskCallReturn type
Read all textFS.readText(path)Result<string, string>
Replace all textFS.writeText(path, text)Result<(), string>
Read all bytesFS.readBytes(path)Result<Bytes, string>
Replace all bytesFS.writeBytes(path, bytes)Result<(), string>
List a directoryFS.list(path)Result<Array<{ kind: string, name: string, sizeBytes: Option<int> }>, string>
Keep a file openopen(path)Result<File, string>

FS accepts a Path or string. The write operations replace the file's contents. Choose a new path or keep a copy before overwriting data you need.

An open File uses these calls.

open(path: string) -> Result<File, string>
file.read() -> Result<string, string>
file.write(s: string) -> Result<(), string>
file.close() -> ()

Use open to acquire the file and read or write for text. For whole-file binary data, use the FS byte operations. File.open, File.create, File.append, readLine, writeLine, and flush are unavailable.

Choose using or defer

Where you need the fileCleanup
Inside one blockusing file = open(path)? { ... } closes it when the block exits
Across nested blocks in a functionFollow let file = open(path)? immediately with defer { file.close() }

using creates an immutable binding in a child scope. Use the open file within that scope. Do not close it manually inside using, because the registered close still runs. Behavior after repeated closing can vary between runtimes.

Both forms clean up on normal exit and exits through return, postfix ?, break, or continue. A fault stops execution immediately. Cleanup after a fault is unspecified.

File access and supported operations

  • File, FS, std.fs, and std.io need a profile that permits filesystem access. A profile defines which operations a program may use.
  • Module imports do not grant access to paths, environment variables, processes, networks, or databases.
  • Opening, reading, and writing return failures as Err values. Handle them with match or propagate them with ?.
  • File hides its internal state and cannot be compared. Avoid using it after closing.
  • File.write has no portable append mode. Binary overloads, buffering, permission controls, and line-by-line methods are not specified for File.
  • using handles one File. User-defined cleanup protocols, multiple-resource using, asynchronous or cancellation cleanup, and cleanup at module exit are not supported.

Continue with Defer & Resources for cleanup order or Null, Option, Result & Faults for error propagation. Find other tasks in Standard Library Overview.