fs
import fs from "fs";
import io from "io";
fs.write_file("notes.txt", "first line\n") or { return 1; };
fs.append_file("notes.txt", "second line\n") or { return 1; };
let text: string = fs.read_file("notes.txt") or {
io.eprintln("cannot read notes.txt: {err}");
return 1;
};fs works on the real file system. Paths are []const u8 in the
platform’s syntax; / works as a separator everywhere, \ on Windows too.
To build paths, use path: path.join(dir, "notes.txt"). Every
failure is an io.IoError.
Whole files
| Function | Does |
|---|---|
read_file(path) -> string or io.IoError | The file’s bytes as a string |
write_file(path, data) -> void or io.IoError | Create or replace the file |
append_file(path, data) -> void or io.IoError | Create the file or add to its end |
copy_file(src, dst) -> void or io.IoError | Copy the bytes, replacing dst |
Opening a file
For more control, open a File. Say what you want to do with it
(Access) and what should happen if it does or doesn’t exist
(Creation):
var f: fs.File = fs.open("data.bin", fs.Access.ReadWrite, fs.Creation.OpenOrCreate) or { return 1; };
defer f.close();
f.seek(16, fs.Whence.Start) or { return 1; };
var buf: [4]u8;
let n: i64 = f.read(buf[0..4]) or { return 1; };Access | |
|---|---|
Read | read only |
Write | write only |
ReadWrite | both |
Append | write, always at the end |
Creation | If the file exists | If it doesn’t |
|---|---|---|
Existing | open it | NotFound |
OpenOrCreate | open it, keep its contents | create it |
CreateNew | AlreadyExists | create it |
Truncate | open it and empty it | create it |
Any Creation other than Existing needs a writing access, whether or
not the file exists: open(p, Access.Read, Creation.Truncate) is
InvalidInput. Opening a directory is IsADirectory.
| Method | Does |
|---|---|
f.read(buf) -> i64 or io.IoError | Read up to buf.len bytes; 0 at the end |
f.write(data) -> i64 or io.IoError | Write some of data at the position |
f.seek(off, whence) -> i64 or io.IoError | Move to off from Start, Current or End; returns the new position |
f.metadata() -> Metadata or io.IoError | Size, kind, modification time |
f.reader() -> io.Reader, f.writer() -> io.Writer | The file as a stream (for write_all, BufWriter, read_line) |
f.close() | Close it; closing twice does nothing |
A File doesn’t close itself: close every file you open, defer f.close(); is the easy way. After close the other methods return
InvalidInput.
Streams make files and buffering work together:
var f: fs.File = fs.open("big.txt", fs.Access.Write, fs.Creation.Truncate) or { return 1; };
var out: io.BufWriter = io.buf_writer(f.writer());
for (i in 0..100000) { out.write_all("row {i}\n") or { return 1; }; }
out.close() or { return 1; };
f.close();Directories and paths
| Function | Does |
|---|---|
exists(path) -> bool | Is there something at path (following links)? |
metadata(path) -> Metadata or io.IoError | What is there (following links) |
mkdir(path) | Create one directory; its parent must exist |
mkdir_all(path) | Create a directory and any missing parents; fine if it exists |
remove(path) | Remove a file, a link, or an empty directory |
remove_all(path) | Remove a directory and everything in it (never following links) |
rename(src, dst) | Move within a volume, replacing a file at dst |
read_dir(path) -> DirIter or io.IoError | The entries of a directory |
temp_dir() -> string | A directory for temporary files |
var it: fs.DirIter = fs.read_dir("assets") or { return 1; };
for (e in it) {
if (e.kind == fs.FileKind.Dir) {
io.println("{e.name}/");
} else {
io.println(e.name);
}
}read_dir yields a DirEntry { name: string; kind: FileKind; } for each
entry except . and .., in no particular order. name is the entry’s
name, not a path: path.join(dir, e.name) makes one. The listing closes
itself after the last entry; if you stop early, call it.close().
temp_dir() is $TMPDIR, $TMP or $TEMP (the first one set), or
/tmp.
Metadata
pub struct Metadata { kind: FileKind; size: i64; modified_ns: i64; read_only: bool; }
pub enum FileKind : u8 { File = 0; Dir = 1; Symlink = 2; Other = 3; }modified_ns is the last modification time in nanoseconds since
1970-01-01 UTC, as precise as the file system keeps it; time.from_unix_nanos
turns it into a date. read_only means nobody may write the file.
metadata follows symbolic links, so its kind is never Symlink; a
DirEntry’s kind is the entry itself and can be.
Platforms
Windows, Linux and macOS support all of fs; names are UTF-8 everywhere
(converted to UTF-16 on Windows). Windows paths longer than 260 characters
are not supported yet. On Uusi (Leivos) an absolute path such as
/system/fonts/x.ttf is a file of Leivos’s storaged: opening, reading,
writing, seeking, metadata (kind, size and modification time), directories,
listings and rename (which replaces a file atomically) work; cwd and
chdir are Unsupported, and without storaged
an absolute path is NotFound. Any other path is the kernel’s (a file of
the boot bundle, read only).
Last modified: