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 #