Paths & directories
Build paths and list, create, or remove directories.
On this page
Paths are plain strings, and valk.fs has functions to join and split them and to work with directories. Relative paths start from the process's working directory.
Join paths#
fs.add joins two parts with exactly one separator. The fs.Path mode offers the same as methods, so calls can be chained:
use valk.fs
fn main() {
println(fs.add("reports/", "/daily.txt")) // reports/daily.txt
let dir: fs.Path = "reports"
let file = dir.add("2026").add("daily.txt")
println(file) // reports/2026/daily.txt
println(file.pop()) // reports/2026
}
A Path converts to and from String by itself; fs.path("x") makes one without a type hint. Building a path never touches the disk.
Split a path#
use valk.fs
fn main() {
let path = "/var/www/site/logo.png"
println(fs.basename(path)) // logo.png
println(fs.dir_of(path)) // /var/www/site
println(fs.extension(path)) // png
println(fs.extension(path, true)) // .png
println(fs.relative("/a/b/c", "/a/d")) // ../b/c
println(fs.mime_type("png")) // image/png
}
| Function | Returns |
|---|---|
fs.resolve(path) |
The absolute path with ., .. and double separators folded |
fs.realpath(path) |
The absolute path with symlinks resolved (the path must exist) |
fs.relative(path, base) |
path as seen from the directory base |
fs.cwd() / fs.chdir(path) |
The working directory, or change it |
fs.home_dir() |
The user's home directory |
fs.exe_path() / fs.exe_dir() |
The running executable, or its directory |
fs.PATH_DIV is the separator of the target: \ on Windows, / elsewhere.
Create and delete directories#
use valk.fs
fn main() {
fs.create_dir_all("build/cache/images") ! return // like mkdir -p
fs.create_dir("build/logs") ! return // the parent must exist
println(fs.is_dir("build/cache")) // true
fs.delete_dir("build/logs") ! return // must be empty
fs.delete_all("build") ! return // everything inside too
println(fs.exists("build")) // false
}
Both create functions take the permission bits as an optional second argument (default 0c755).
List a directory#
fs.files_in returns an array of paths. Its options pick recursion, files, directories, and names relative to the directory:
use valk.fs
fn main() {
fs.create_dir_all("site/css") ! return
fs.write("site/index.html", "") ! return
fs.write("site/css/main.css", "") ! return
let all = fs.files_in("site", recursive: true, dirs: false, relative: true) ! return
all.sort()
println(all.join(", ")) // css/main.css, index.html
let css = fs.glob("site/**/*.css")
println(css.join(", ")) // site/css/main.css
}
fs.glob understands *, ?, [a-z] and ** for any number of directories, and returns the matches sorted. The order of files_in is not defined.
For a large directory, fs.read_dir returns one name at a time without building an array. It skips . and ..:
use valk.fs
fn main() {
fs.create_dir_all("inbox") ! return
fs.write("inbox/a.txt", "") ! return
let entries = fs.read_dir("inbox") ! return
defer entries.close() _
while true {
let name = entries.next() ! return
if !isset(name) : break
println(name) // a.txt
}
}
The iterator closes itself at the end; the defer covers stopping early.
Temporary files#
use valk.fs
fn main() {
let dir = fs.create_temp_dir("myapp-") ! return
let file = fs.create_temp_file("upload-", ".json", dir) ! return
fs.write(file, "{}") ! return
println(fs.exists(file)) // true
fs.delete_all(dir) ! return
}
Both create a new, empty entry with a unique name in fs.temp_dir() (or the directory given last) and return its path. Delete them when you are done.
