std.fs

Files, directories, metadata, and filesystem watching.

Importuse std.fs

Types

struct Stat#

File metadata from std.fs.stat. A failed stat is exists = false with zeroed fields.

size: int

Length in bytes; 0 for a directory or a failed stat.

mtime_ms: int

Last modification time in milliseconds since the Unix epoch.

is_dir: bool

Whether the entry is a directory.

is_file: bool

Whether the entry is a regular file.

exists: bool

Whether the stat succeeded at all; false zeroes every other field.

struct FsEvent#

Raw filesystem notification from Watcher.next.

kind: string

What happened, as the platform reported it.

path: string

The path the event concerns.

struct File#

A partial-I/O handle from std.fs.open.

An opaque handle: only std.fs can produce one, and its contents are not reachable from moon source.

use std.fs.File

fn first_bytes(file: *File, count: int) -> string {
  file.read_at(0, count)
}

fn main() {
  let mut file = std.fs.open("main.mn", "r")
  defer file.close()
  println(first_bytes(&file, 5))
}
_handle: NativeHandle

The native resource.

struct Watcher#

A recursive filesystem watcher from std.fs.watch.

An opaque handle: only std.fs can produce one, and its contents are not reachable from moon source.

_handle: NativeHandle

The native resource.

Functions

extern fn open(path: string, mode: string) -> File#

Opens an opaque partial-I/O file handle in mode r, w, a, or rw.

  • path: File to open.
  • mode: One of r, w, a, or rw.
let path = std.fs.temp_dir() + "/notes.txt"
let _ = std.fs.write_file(path, "")
let file = std.fs.open(path, "rw")
let _ = std.fs.write(file, "line one\n")
std.fs.flush(file)
let _ = std.fs.seek(file, 0)
println(std.fs.read(file, 4)) // line
println(std.fs.tell(file))    // 4
println(std.fs.size(file))    // 9
std.fs.close(file)
extern fn try_open(path: string, mode: string) -> Result<File, Error>#

Result-returning twin of open.

  • path: File to open.
  • mode: One of r, w, a, or rw.
match std.fs.try_open("missing/deep.txt", "r") {
  ok(file) => std.fs.close(file),
  err(failure) => println(failure.name), // NotFound
}
extern fn read(file: File, count: int) -> string#

Reads at most count bytes from the logical cursor; an empty string is EOF.

  • file: Handle to read from.
  • count: Upper bound on the bytes returned.
extern fn read_at(file: File, offset: int, count: int) -> string#

Reads a byte window without moving the cursor; calls on one handle may overlap.

  • file: Handle to read from.
  • offset: Absolute byte offset to read at.
  • count: Upper bound on the bytes returned.
let path = std.fs.temp_dir() + "/window.txt"
let _ = std.fs.write_file(path, "abcdefgh")
let file = std.fs.open(path, "rw")
println(std.fs.read_at(file, 2, 3)) // cde
let _ = std.fs.write_at(file, 0, "AB")
println(std.fs.read_at(file, 0, 4)) // ABcd
std.fs.close(file)
extern fn read_line(file: File) -> Future<string>#

Returns a future that reads one line without its newline; an empty string is EOF or an empty line.

  • file: Handle to read from.
async fn main() {
  let file = std.fs.open("notes.txt", "r")
  let first = await std.fs.read_line(file)
  println(first)
  std.fs.close(file)
}
extern fn try_read_line(file: File) -> Future<Optional<string>>#

Returns a future that reads one line as some(string), or none at EOF.

  • file: Handle to read from.
async fn main() {
  let file = std.fs.open("notes.txt", "r")
  let mut more = true
  while more {
    match await std.fs.try_read_line(file) {
      some(line) => println(line),
      none => { more = false },
    }
  }
  std.fs.close(file)
}
extern fn write(file: File, data: string) -> int#

Writes all bytes at the logical cursor and returns the byte count.

  • file: Handle to write to.
  • data: Bytes to write at the cursor.
extern fn write_at(file: File, offset: int, data: string) -> int#

Writes a byte window without moving the cursor; calls on one handle may overlap. Rejected in append mode.

  • file: Handle to write to.
  • offset: Absolute byte offset to write at.
  • data: Bytes to write.
extern fn seek(file: File, offset: int) -> int#

Moves the logical cursor to an absolute byte offset.

  • file: Handle to move.
  • offset: Absolute byte offset to move the cursor to.
extern fn seek_end(file: File, offset: int) -> int#

Moves the logical cursor relative to the current file size.

  • file: Handle to move.
  • offset: Byte offset relative to the current file size; negative moves back from the end.
let path = std.fs.temp_file("tail-")
let _ = std.fs.write_file(path, "abcdefgh")
let file = std.fs.open(path, "r")
let _ = std.fs.seek_end(file, -3)
println(std.fs.read(file, 3)) // fgh
std.fs.close(file)
extern fn tell(file: File) -> int#

Returns the logical cursor.

  • file: Handle to query.
extern fn size(file: File) -> int#

Returns the current file size.

  • file: Handle to measure.
extern fn flush(file: File)#

Synchronizes pending file contents and metadata.

  • file: Handle whose pending contents and metadata are synchronized.
extern fn close(resource: File)#

Closes a File or Watcher resource. Repeated close calls are no-ops; closing a Watcher wakes pending next calls.

  • resource: File or Watcher to close.
extern fn watch(paths: [string]) -> Watcher#

Recursively watches paths for filesystem changes.

  • paths: Roots to watch, each recursively.
async fn main() {
  let watcher = std.fs.watch(["."])
  let event = await std.fs.next(watcher)
  println("${event.kind}: ${event.path}")
  std.fs.close(watcher)
}
extern fn next(watcher: Watcher) -> Future<FsEvent>#

Returns a future for the next raw filesystem event.

  • watcher: Watcher to take the next event from.
extern fn try_next(watcher: Watcher) -> Future<Optional<FsEvent>>#

Like next, but resolves to none once the watcher is closed.

  • watcher: Watcher to take the next event from.
async fn main() {
  let watcher = std.fs.watch(["src"])
  let mut open = true
  while open {
    match await std.fs.try_next(watcher) {
      some(event) => println(event.path),
      none => { open = false }, // the watcher was closed
    }
  }
}
extern fn read_file(path: string) -> string#

Reads file.

  • path: File to read whole.
let path = std.fs.temp_dir() + "/greeting.txt"
let _ = std.fs.write_file(path, "moon")
println(std.fs.read_file(path))   // moon
let _ = std.fs.append_file(path, "!")
println(std.fs.read_file(path))   // moon!
let _ = std.fs.remove_file(path)
println(std.fs.file_exists(path)) // false
fn read_lines(path: string) -> [string]#

Reads lines.

  • path: File to read and split at newlines.
let path = std.fs.temp_dir() + "/list.txt"
let _ = std.fs.write_lines(path, ["alpha", "beta"])
println(std.fs.read_lines(path)) // ["alpha", "beta"]
extern fn write_file(path: string, data: string) -> bool#

Writes file.

  • path: File to create or truncate.
  • data: Bytes to write.
extern fn append_file(path: string, data: string) -> bool#

Appends file.

  • path: File to append to, created when missing.
  • data: Bytes to append.
fn write_lines(path: string, lines: [string]) -> bool#

Writes lines.

  • path: File to create or truncate.
  • lines: Lines to write, each terminated with a newline.
extern fn file_exists(path: string) -> bool#

Reports whether the filesystem entry exists.

  • path: Entry to test for.
extern fn remove_file(path: string) -> bool#

Removes file.

  • path: File to delete.
extern fn try_read_file(path: string) -> Result<string, Error>#

Attempts to read file, returning failures as error values.

  • path: File to read whole.
match std.fs.try_read_file("missing.txt") {
  ok(text) => println(text),
  err(failure) => println(failure.name), // NotFound
}
fn try_read_lines(path: string) -> Result<[string], Error>#

Attempts to read lines, returning failures as error values.

  • path: File to read and split at newlines.
extern fn try_write_file(path: string, data: string) -> Result<void, Error>#

Attempts to write file, returning failures as error values.

  • path: File to create or truncate.
  • data: Bytes to write.
// try_append_file, try_write_lines, and try_remove_file share this shape.
fn save(path: string, entry: string) -> Result<void, Error> {
  std.fs.try_write_file(path, entry)?
  std.fs.try_append_file(path, "\n")
}

fn main() {
  let _ = save(std.fs.temp_dir() + "/log.txt", "entry")
}
extern fn try_append_file(path: string, data: string) -> Result<void, Error>#

Attempts to append file, returning failures as error values.

  • path: File to append to, created when missing.
  • data: Bytes to append.
fn try_write_lines(path: string, lines: [string]) -> Result<void, Error>#

Attempts to write lines, returning failures as error values.

  • path: File to create or truncate.
  • lines: Lines to write, each terminated with a newline.
extern fn try_remove_file(path: string) -> Result<void, Error>#

Attempts to remove file, returning failures as error values.

  • path: File to delete.
fn read_bytes(path: string) -> string#

Reads bytes.

  • path: File to read whole, byte-faithfully.
fn write_bytes(path: string, data: string) -> bool#

Writes bytes.

  • path: File to create or truncate.
  • data: Bytes to write verbatim.
extern fn stat(path: string) -> Stat#

Returns filesystem metadata for a path.

  • path: Entry to describe.
let path = std.fs.temp_dir() + "/probe.txt"
let _ = std.fs.write_file(path, "12345")
let info = std.fs.stat(path)
println(info.is_file) // true
println(info.size)    // 5
println(std.fs.stat("no-such-entry").exists) // false
extern fn set_mtime(path: string, epoch_ms: int) -> bool#

Sets a file's modification time to an epoch-milliseconds value.

  • path: Filesystem path to act on.
  • epoch_ms: New modification time in milliseconds since the Unix epoch.
let path = std.fs.temp_file("stamp-")
let _ = std.fs.set_mtime(path, 1700000000000)
println(std.fs.stat(path).mtime_ms) // 1700000000000
extern fn list_dir(path: string) -> [string]#

Returns the immediate entries of a directory.

  • path: Directory to list; names only, not full paths.
extern fn walk(path: string) -> [string]#

Returns filesystem entries recursively.

  • path: Directory to walk recursively.
extern fn mkdir(path: string) -> bool#

Creates one directory, returning false on failure.

  • path: Directory to create; its parent must exist.
let dir = std.fs.temp_dir() + "/single"
println(std.fs.mkdir(dir))          // true
println(std.fs.mkdir(dir + "/a/b")) // false — parent a does not exist
println(std.fs.rmdir(dir))          // true — still empty
extern fn mkdir_all(path: string) -> bool#

Creates a directory and every missing parent.

  • path: Directory to create along with every missing parent.
let root = std.fs.temp_dir() + "/demo-tree"
let _ = std.fs.mkdir_all(root + "/src/deep")
let _ = std.fs.write_file(root + "/src/deep/a.txt", "a")
println(std.fs.list_dir(root)) // ["src"]
println(std.fs.walk(root))     // ["src", "src/deep", "src/deep/a.txt"]
let _ = std.fs.remove_all(root)
extern fn rmdir(path: string) -> bool#

Removes an empty directory.

  • path: Directory to remove; it must already be empty.
extern fn remove_all(path: string) -> bool#

Removes all.

  • path: Entry to remove, together with everything under it.
extern fn rename(from: string, to: string) -> bool#

Renames or moves a filesystem entry.

  • from: Existing path.
  • to: New path, replaced if it exists.
let dir = std.fs.temp_dir()
let _ = std.fs.write_file(dir + "/draft.txt", "v1")
let _ = std.fs.copy_file(dir + "/draft.txt", dir + "/backup.txt")
let _ = std.fs.rename(dir + "/draft.txt", dir + "/final.txt")
println(std.fs.read_file(dir + "/final.txt"))   // v1
println(std.fs.file_exists(dir + "/draft.txt")) // false
extern fn copy_file(from: string, to: string) -> bool#

Copies one file to another.

  • from: File to read.
  • to: File to create or overwrite.
extern fn temp_dir() -> string#

Returns the platform temporary-directory path.

let scratch = std.path.join([std.fs.temp_dir(), "session.log"])
let _ = std.fs.write_file(scratch, "started\n")
extern fn temp_file(prefix: string) -> string#

Creates a temporary file with the supplied prefix.

  • prefix: Prefix for the generated file name.
let path = std.fs.temp_file("report-")
println(std.fs.file_exists(path)) // true — the file is created
let _ = std.fs.remove_file(path)