fs
files, directories, paths, JSON and CSV
Example results generated on 2026-10-08. Ones using
now,todayor randomness will differ when you run them: press Run on any example to run it in your browser, after editing it if you like.
tables
# ls(dir?), glob(pat) give name, type, size, modified
# glob: * and ? within a name, ** across directories
Functions
| function | description |
|---|---|
read_file(path: str) | file contents as a string |
write_file(path: str, v: any) | replace a file with v as text; a list is one item per line, a table is CSV |
append_file(path: str, v: any) | add v to the end of a file as text, creating it if needed; a list is one item per line |
exists(path: str) | whether a file or directory exists |
is_dir(path: str) | whether path is a directory |
ls(dir?: str) | a directory’s entries as a table: name, type, size, modified |
glob(pat: str) | paths matching pat as a table like ls; * and ? match within a name, ** across directories |
file_size(path: str) | size in bytes, as a quantity |
mtime(path: str) | when the file was last modified |
rm(path: str) | delete a file or an empty directory |
mv(from: str, to: str) | move or rename a file or directory, creating missing folders |
cp(from: str, to: str) | copy a file, creating missing folders |
mkdir(path: str) | create a directory and any missing parents |
path_join(a: str, b: str, ...) | join path pieces with the OS separator |
basename(path: str) | the last piece of a path, or nil |
dirname(path: str) | everything before the last piece, or nil |
ext(path: str) | the extension without its dot, or nil |
stem(path: str) | the last piece without its extension, or nil |
abspath(path: str) | path made absolute from the current directory; need not exist |
cwd() | the current directory |
cd(dir?: str) | change the current directory, home by default; returns the new one |
from_json(s: str) | parse JSON: objects become maps, arrays lists |
to_json(v: any) | v as JSON; values JSON lacks (quantities, fractions, dates) become strings |
from_csv(s: str, header?: bool) | parse CSV; with a header row (the default) a table, else a list of rows. Numbers become numbers, empty cells nil |
to_csv(rows: table|list) | CSV text from a table, a list of maps, or a list of lists |
read_file
read_file(path: str): file contents as a string
read_file("notes.txt").lines.len
read_file("data.json").from_json
See also: write_file, lines, from_csv
write_file
write_file(path: str, v: any): replace a file with v as text; a list is one item per line, a table is CSV
write_file("out.txt", [1, 2, 3])
write_file("files.csv", ls())
See also: read_file, append_file
append_file
append_file(path: str, v: any): add v to the end of a file as text, creating it if needed; a list is one item per line
append_file("log.txt", ["started {now}"])
See also: write_file
exists
exists(path: str): whether a file or directory exists
exists("Cargo.toml")
See also: is_dir
is_dir
is_dir(path: str): whether path is a directory
is_dir("src")
See also: exists
ls
ls(dir?: str): a directory’s entries as a table: name, type, size, modified
ls()
ls("src").where(|f| f.type == "file").name
glob
glob(pat: str): paths matching pat as a table like ls; * and ? match within a name, ** across directories
glob("**/*.rs").size.sum
glob("*.csv").name
See also: ls
file_size
file_size(path: str): size in bytes, as a quantity
file_size("Cargo.lock") to KiB
See also: mtime, human_bytes
mtime
mtime(path: str): when the file was last modified
now - mtime("Cargo.lock") to h
See also: file_size
rm
rm(path: str): delete a file or an empty directory
rm("out.txt")
mv
mv(from: str, to: str): move or rename a file or directory, creating missing folders
mv("draft.txt", "final.txt")
cp
cp(from: str, to: str): copy a file, creating missing folders
cp("data.csv", "backup/data.csv")
See also: mv
mkdir
mkdir(path: str): create a directory and any missing parents
mkdir("out/2026/10")
See also: rm
path_join
path_join(a: str, b: str, ...): join path pieces with the OS separator
path_join("a", "b.txt")
# → "a/b.txt"
basename
basename(path: str): the last piece of a path, or nil
"a/b/c.txt".basename
# → "c.txt"
dirname
dirname(path: str): everything before the last piece, or nil
"a/b/c.txt".dirname
# → "a/b"
See also: basename
ext
ext(path: str): the extension without its dot, or nil
"a/b.tar.gz".ext
# → "gz"
"README".ext
# → nil
See also: stem
stem
stem(path: str): the last piece without its extension, or nil
"a/b.tar.gz".stem
# → "b.tar"
abspath
abspath(path: str): path made absolute from the current directory; need not exist
abspath("src")
See also: cwd
cwd
cwd(): the current directory
cwd()
cd
cd(dir?: str): change the current directory, home by default; returns the new one
cd("src")
cd("..")
cd()
See also: cwd
from_json
from_json(s: str): parse JSON: objects become maps, arrays lists
"\{\"a\": [1, 2.5, null]}".from_json
# → {a: [1, 2.5, nil]}
to_json
to_json(v: any): v as JSON; values JSON lacks (quantities, fractions, dates) become strings
{a: [1, nil], b: 5 km}.to_json
# → "{\"a\":[1,null],\"b\":\"5 km\"}"
See also: from_json
from_csv
from_csv(s: str, header?: bool): parse CSV; with a header row (the default) a table, else a list of rows. Numbers become numbers, empty cells nil
"name,n\nx,1".from_csv
# → table([{name: "x", n: 1}])
"1,2\n3,4".from_csv(false)
# → [[1, 2], [3, 4]]
to_csv
to_csv(rows: table|list): CSV text from a table, a list of maps, or a list of lists
[{a: 1, b: "x,y"}].to_csv
# → a,b
# → 1,"x,y"
# →
[[1, 2], [3, 4]].to_csv
# → 1,2
# → 3,4
# →
See also: from_csv
More examples
fs
# JSON to a value
"\{\"a\": [1, 2]}".from_json.a.sum
# → 3
# CSV to a table
"name,n\nx,1\ny,2".from_csv.n.sum
# → 3
# path pieces
["a/b.tar.gz".stem, "a/b.tar.gz".ext]
# → ["b.tar", "gz"]