ℇbn/notes

2025-03-21T05:29:32

C3: Reading and writing files

New concepts

Optionals

An optional is either a value of type t or a fault, optional types are denoted by t?, e.g. int?. Optionals can be handled using try and catch. The ! operator can be used to unwrap and re-throw a potential fault to the caller.

Defer

defer is used to ensure that something is performed at the end of a scope. For example closing a file.

Slices

A slice denoted by type[] is a struct containing a pointer and a size. An array can be sliced using the range syntax, for example

array[<start-index> : <slice-length>]

Example: Reading a file

import std::io;
import std::io::file;

fn char[]? load_file(String filename)
{
    File fh = file::open(filename, "rb")!;
    defer (void)fh.close();

    usz len = fh.seek(0, END)!;
    fh.seek(0, SET)!;

    char* buffer = malloc(len);
    usz read = fh.read(buffer[:len])!;

    return buffer[:len];
}

fn int main()
{
    char[]? data = load_file("input.in");

    if (catch err = data)
    {
        // handle err
        io::eprintfn("Error: could not load file");
        return 1;
    }
    io::printfn("%s", (String)data);

    return 0;
}

Note: A similar implementation of load_file is already provided by the standard library as file::load.

Example: Writing to file

import std::io;
import std::io::file;

String out_file = "output.out";

fn void? save_file(String filename, char[] data)
{
    File fh = file::open(filename, "wb")!;
    defer (void)fh.close();

    fh.write(data)!;
}

fn int main()
{
    char[] data = "Hello\nWorld\n";

    if (catch err = save_file(out_file, data))
    {
        io::printfn("Error: unable to write to %s", out_file);
    }

    return 0;
}

Note: Again, a similar implementation of save_file is already provided by the standard library as file::save.

Resources