std.os
Operating system interface module: file handle read/write, directory operations, environment variables, and working directory.
use std.osAll functions in this module depend on operating system capabilities and are not exported on the
wasm32target.
File Handle Model
Handles are passed by reference (#337 fixed): The signatures of
read/write/seek/tell/flush/closeare all(file: &File, ...), so handles can be used repeatedly:yaoxiangf = os.open(p, "w") os.write(f, "hello world") os.close(f)Read/write after positioning (the reason
seekexists) is also available:yaoxiangr = os.open(p, "r") os.seek(r, 6) tail = os.read(r, 5) // "world" os.close(r)Before the fix, signatures had no
&, so handles were passed by value → linear ownership → became invalid after one use, andopen → write → closewould reportE2014.If you want to avoid manually managing handles, you can still use the convenience functions that don't open handles:
std.io.read_file/write_file/append_file, or this module'sappend_file.
open returns an Int-typed file descriptor (the engine internally maintains a handle table), so the File in signatures is actually Int.
Content is flushed to disk immediately after writing — no explicit close is needed:
use std.assert
use std.io
use std.os
main: () -> Void = {
p = "__yx_doc_open.txt"
n = os.write(os.open(p, "w"), "hello")
assert(n == 5)
assert(io.read_file(p) == "hello")
os.remove(p)
}Modes supported by open:
| Mode | Meaning |
|---|---|
r | Read-only, file must exist |
w | Write-only, create or truncate |
a | Append, create or append to end |
r+ | Read/write, file must exist |
w+ | Read/write, create or truncate |
a+ | Read/write, create or append |
Function List
| Function | Signature |
|---|---|
open | (path: &String, mode: &String) -> File |
close | (file: &File) -> Void |
read | (file: &File, n: Int) -> String |
write | (file: &File, content: String) -> Int |
seek | (file: &File, offset: Int) -> Bool |
tell | (file: &File) -> Int |
flush | (file: &File) -> Void |
mkdir | (path: &String) -> Bool |
rmdir | (path: &String) -> Bool |
read_dir | (path: &String) -> String |
remove | (path: &String) -> Bool |
exists | (path: &String) -> Bool |
is_file | (path: &String) -> Bool |
is_dir | (path: &String) -> Bool |
copy | (src: &String, dst: &String) -> Bool |
rename | (old: &String, new: &String) -> Bool |
get_env | (name: &String) -> String |
set_env | (name: &String, value: &String) -> Void |
args | () -> String |
chdir | (path: &String) -> Bool |
getcwd | () -> String |
append_file | (path: &String, content: &String) -> Bool |
open
open: (path: &String, mode: &String) -> FileOpen a file and return a file descriptor.
path—— file path (read-only borrow)mode—— open mode, see the table above
Returns: an Int descriptor allocated from the internal handle table. This handle can only be used once — any downstream call will move it (see File Handle Model), so open is usually inlined into a single call.
Error: throws E6007 if the mode is invalid, the file does not exist, or there are insufficient permissions.
Since the handle can only be used once (#337), the return value is usually inlined directly into a downstream call.
use std.assert
use std.os
main: () -> Void = {
p = "__yx_doc_open_only.txt"
f = os.open(p, "w")
assert(os.exists(p))
os.remove(p)
}close
close: (file: &File) -> VoidClose the file handle and release the table entry.
Since the handle can only be used once, close only makes sense in scenarios where the file is "opened and not used for anything else"; written content is already flushed to disk when write returns, so explicit closing is usually not needed.
Error: throws E6007 if the descriptor is invalid (not opened or already closed).
use std.os
main: () -> Void = {
p = "__yx_doc_close.txt"
f = os.open(p, "w")
os.close(f)
os.remove(p)
}read
read: (file: &File, n: Int) -> StringRead at most n bytes from the current read/write position.
file—— file descriptorn—— expected number of bytes to read
Returns: the actual content read (may be shorter than n, returns an empty string when the end of file is reached). Invalid UTF-8 bytes are returned as replacement characters, without error. Error: throws E6007 if the descriptor is invalid or the read fails.
use std.assert
use std.io
use std.os
main: () -> Void = {
p = "__yx_doc_read.txt"
io.write_file(p, "abcdef")
part = os.read(os.open(p, "r"), 3)
assert(part == "abc")
os.remove(p)
}write
write: (file: &File, content: String) -> IntWrite all of content at the current read/write position.
content—— passed by value
Returns: the number of bytes written. Error: throws E6007 if the descriptor is invalid or the write fails.
use std.assert
use std.os
main: () -> Void = {
p = "__yx_doc_write.txt"
n = os.write(os.open(p, "w"), "hello")
assert(n == 5)
os.remove(p)
}seek
seek: (file: &File, offset: Int) -> BoolMove the read/write position to absolute offset offset (relative to the start of the file).
offset—— target byte offset, must be non-negative
Returns: true on success. Error: throws E6007 if the descriptor is invalid or the offset is invalid.
use std.assert
use std.io
use std.os
main: () -> Void = {
p = "__yx_doc_seek.txt"
io.write_file(p, "abcdef")
ok = os.seek(os.open(p, "r"), 2)
assert(ok)
os.remove(p)
}tell
tell: (file: &File) -> IntReturn the byte offset of the current read/write position.
Error: throws E6007 if the descriptor is invalid.
use std.assert
use std.os
main: () -> Void = {
p = "__yx_doc_tell.txt"
pos = os.tell(os.open(p, "w"))
assert(pos == 0)
os.remove(p)
}flush
flush: (file: &File) -> VoidFlush buffered content to disk.
Error: throws E6007 if the descriptor is invalid or flushing fails.
use std.assert
use std.os
main: () -> Void = {
p = "__yx_doc_flush.txt"
os.flush(os.open(p, "w"))
assert(os.exists(p))
os.remove(p)
}Directory Operations
mkdir
mkdir: (path: &String) -> BoolCreate a single-level directory (does not recursively create parent directories).
Returns: true on success. Error: throws E6007 if the parent directory does not exist or the directory already exists.
use std.assert
use std.os
main: () -> Void = {
d = "__yx_doc_mkdir"
assert(os.mkdir(d))
assert(os.is_dir(d))
os.rmdir(d)
}rmdir
rmdir: (path: &String) -> BoolDelete an empty directory.
Returns: true on success. Error: throws E6007 if the directory does not exist or is not empty.
use std.assert
use std.os
main: () -> Void = {
d = "__yx_doc_rmdir"
os.mkdir(d)
assert(os.rmdir(d))
assert(!os.exists(d))
}read_dir
read_dir: (path: &String) -> StringList entry names in the directory.
Returns: a single string with entry names joined by \n (not a List). Error: throws E6007 if the directory does not exist or there are insufficient permissions.
use std.assert
use std.os
use std.string
main: () -> Void = {
d = "__yx_doc_read_dir"
os.mkdir(d)
names = os.read_dir(d)
// Empty directory returns empty string
assert(string.is_empty(names))
os.rmdir(d)
}Path and File Utilities
remove
remove: (path: &String) -> BoolDelete a file; semantically equivalent to remove_file (cannot delete directories; use rmdir for directories).
Returns: true on success. Error: throws E6007 if the file does not exist or the path is a directory.
use std.assert
use std.io
use std.os
main: () -> Void = {
p = "__yx_doc_remove.txt"
io.write_file(p, "x")
assert(os.remove(p))
assert(!os.exists(p))
}exists
exists: (path: &String) -> BoolWhether the path exists (file or directory). Does not throw; returns false if it does not exist.
use std.assert
use std.os
main: () -> Void = {
assert(os.exists("."))
assert(!os.exists("__yx_definitely_missing_path__"))
}is_file
is_file: (path: &String) -> BoolWhether the path is a regular file. Returns false for directories and false for non-existent paths.
use std.assert
use std.os
main: () -> Void = {
assert(!os.is_file("."))
}is_dir
is_dir: (path: &String) -> BoolWhether the path is a directory. Returns false for files and false for non-existent paths.
use std.assert
use std.os
main: () -> Void = {
assert(os.is_dir("."))
}copy
copy: (src: &String, dst: &String) -> BoolCopy a file. Overwrites if the destination already exists.
Returns: true on success. Error: throws E6007 if the source file does not exist or there are insufficient permissions.
use std.assert
use std.io
use std.os
main: () -> Void = {
a = "__yx_doc_copy_a.txt"
b = "__yx_doc_copy_b.txt"
io.write_file(a, "data")
assert(os.copy(a, b))
assert(io.read_file(b) == "data")
os.remove(a)
os.remove(b)
}rename
rename: (old: &String, new: &String) -> BoolRename or move a file.
Returns: true on success. Error: throws E6007 if the source file does not exist or the destination already exists.
use std.assert
use std.io
use std.os
main: () -> Void = {
a = "__yx_doc_rename_a.txt"
b = "__yx_doc_rename_b.txt"
io.write_file(a, "data")
assert(os.rename(a, b))
assert(os.exists(b))
os.remove(b)
}append_file
append_file: (path: &String, content: &String) -> BoolAppend write (convenience function that does not open a handle). Creates the file if it does not exist.
Returns: true on success. Error: throws E6007 if there are insufficient permissions.
This is a same-name, same-kind interface to
std.io.append_file; both modules provide it with consistent behavior.
use std.assert
use std.io
use std.os
main: () -> Void = {
p = "__yx_doc_os_append.txt"
io.write_file(p, "a")
os.append_file(p, "b")
assert(io.read_file(p) == "ab")
os.remove(p)
}Environment Variables
get_env
get_env: (name: &String) -> StringRead an environment variable.
Returns: the variable's value; returns an empty string if the variable does not exist (does not throw). Therefore, it cannot distinguish "not set" from "set to empty string".
use std.assert
use std.os
use std.string
main: () -> Void = {
// PATH is guaranteed to exist on mainstream platforms
path = os.get_env("PATH")
assert(string.len(path) > 0)
// Non-existent variable returns empty string
assert(string.is_empty(os.get_env("__YX_DEFINITELY_MISSING__")))
}set_env
set_env: (name: &String, value: &String) -> VoidSet an environment variable (affects the current process).
use std.assert
use std.os
main: () -> Void = {
os.set_env("__YX_DOC_ENV", "hello")
assert(os.get_env("__YX_DOC_ENV") == "hello")
}Process and Working Directory
args
args: () -> StringReturn command-line arguments.
Returns: a single string with all argv values joined by \n (not a List). The first item is the path of the program itself.
use std.assert
use std.os
use std.string
main: () -> Void = {
argv = os.args()
assert(string.len(argv) > 0)
}chdir
chdir: (path: &String) -> BoolSwitch the current working directory.
Returns: true on success. Error: throws E6007 if the directory does not exist.
use std.assert
use std.os
main: () -> Void = {
before = os.getcwd()
assert(os.chdir(".."))
assert(os.chdir(before)) // switch back
assert(os.getcwd() == before)
}getcwd
getcwd: () -> StringReturn the absolute path of the current working directory.
Error: throws E6007 if it cannot be obtained.
use std.assert
use std.os
use std.string
main: () -> Void = {
cwd = os.getcwd()
assert(string.len(cwd) > 0)
}Related
std.io—— whole-file read/write convenience functions- Error Code Reference ——
E6007general runtime error
