Virtual File System — unified file, path and filesystem utilities for Apero.
Combines path operations, high-level file actions (atomic writes, checksums, temp resources, file locking) and file discovery.
Concurrent operations (batch checksums, multi-file copies) use
Arrea.Parallel.run_sync for parallelism.
Security note
atomic_write/2 always creates the temp file in the same directory as the
target to guarantee rename(2) atomicity (cross-device renames fall back
to copy+delete).
Summary
Functions
Writes content to path atomically using a temp-file + rename.
Returns the filename without extension.
Computes the checksum of a file by streaming its contents in 64KB chunks. Never loads the entire file into memory.
Computes checksums for multiple files in parallel.
Copies source to dest. Creates parent directories as needed.
Returns {:ok, bytes_copied}.
Recursively copies a directory from source to dest.
Copies multiple files in parallel using Arrea.Parallel.run_sync.
Deletes a file. Returns :ok even if the file did not exist.
Recursively deletes a directory and all its contents.
Returns true if the given path is an existing directory.
Returns disk usage information for the filesystem containing path.
Creates the directory and all parents. Idempotent.
Returns true if the given path exists (file, directory or symlink).
Expands ~ and relative path segments to an absolute path.
Returns the extension of a file path.
Returns true if the given path is an existing regular file.
Generates a visual ASCII tree from a list of file paths.
Lists files matching a glob pattern in dir.
Moves source to dest. Uses rename when possible, falls back to copy+delete
on cross-device moves.
Returns the last modification time of a file as a NaiveDateTime.
Prints an ASCII directory tree of path to stdout.
Reads a text file and returns its contents.
Reads all non-empty, non-comment lines from a file.
Returns the file size in bytes.
Creates a symbolic link at link_path pointing to target.
Stops a file watcher by PID.
Starts watching dirs for file system changes.
Acquires an advisory lock on lock_path, runs fun, then releases it.
Creates a temporary directory, yields its path to fun, then deletes it.
The directory is deleted even when fun raises.
Creates a temporary file, yields its path to fun, then deletes it.
The file is deleted even when fun raises.
Writes text to a file, creating parent directories as needed.
Functions
Writes content to path atomically using a temp-file + rename.
The temp file is created in the same directory as path to ensure the
rename is atomic on POSIX systems. Parent directories are created as needed.
Examples
iex> path = Path.join(System.tmp_dir!(), "apero_atomic_test.txt")
iex> :ok = Apero.VFS.atomic_write(path, "hello")
iex> File.read!(path)
"hello"
iex> File.rm!(path)
:ok
Returns the filename without extension.
Examples
iex> Apero.VFS.basename("path/to/file.ex")
"file"
Computes the checksum of a file by streaming its contents in 64KB chunks. Never loads the entire file into memory.
Supported algorithms: :sha256, :sha512, :md5, :sha.
Returns the lowercase hex-encoded digest.
Examples
iex> path = Path.join(System.tmp_dir!(), "apero_cs_test.bin")
iex> File.write!(path, "hello")
iex> {:ok, digest} = Apero.VFS.checksum(path, :sha256)
iex> String.length(digest)
64
iex> File.rm!(path)
:ok
@spec checksum_many([binary()], :sha256 | :sha512 | :md5 | :sha) :: %{ required(binary()) => {:ok, binary()} | {:error, binary()} }
Computes checksums for multiple files in parallel.
Returns a map of path => {:ok, digest} | {:error, reason}.
@spec copy(binary(), binary()) :: {:ok, non_neg_integer()} | {:error, binary()}
Copies source to dest. Creates parent directories as needed.
Returns {:ok, bytes_copied}.
Recursively copies a directory from source to dest.
@spec copy_many([{binary(), binary()}]) :: [ok: non_neg_integer(), error: binary()]
Copies multiple files in parallel using Arrea.Parallel.run_sync.
Each element of pairs is a {source, dest} tuple.
Returns [{:ok, bytes} | {:error, reason}] in the same order.
Deletes a file. Returns :ok even if the file did not exist.
Recursively deletes a directory and all its contents.
Returns true if the given path is an existing directory.
Returns disk usage information for the filesystem containing path.
Returns a map with :total_mb, :used_mb, :free_mb, :use_pct.
Only supported on Unix-like systems.
@spec ensure_dir(binary()) :: :ok | {:error, File.posix()}
Creates the directory and all parents. Idempotent.
Returns true if the given path exists (file, directory or symlink).
Expands ~ and relative path segments to an absolute path.
Returns the extension of a file path.
Examples
iex> Apero.VFS.extension("archive.tar.gz")
".gz"
Returns true if the given path is an existing regular file.
Generates a visual ASCII tree from a list of file paths.
Returns a printable string with ├─ and └─ connectors.
The last item at each level uses └─, all others use ├─.
Examples
iex> Apero.VFS.generate_tree(["a"])
"└─ a"
Lists files matching a glob pattern in dir.
Options
:recursive— recurse into subdirectories (default:false)
Moves source to dest. Uses rename when possible, falls back to copy+delete
on cross-device moves.
@spec mtime(binary()) :: {:ok, NaiveDateTime.t()} | {:error, File.posix()}
Returns the last modification time of a file as a NaiveDateTime.
@spec print_tree(binary()) :: :ok
Prints an ASCII directory tree of path to stdout.
Reads a text file and returns its contents.
Reads all non-empty, non-comment lines from a file.
Lines starting with # and blank lines are removed. Content is trimmed.
@spec size(binary()) :: {:ok, non_neg_integer()} | {:error, File.posix()}
Returns the file size in bytes.
Creates a symbolic link at link_path pointing to target.
@spec unwatch(pid()) :: :ok
Stops a file watcher by PID.
@spec watch([binary()], ([{binary(), [atom()]}] -> any()), keyword()) :: {:ok, pid()} | {:error, term()}
Starts watching dirs for file system changes.
Calls callback with a list of {path, events} tuples after each
debounce window.
Options
:debounce_ms— debounce delay in ms (default:100):name— optional name for the watcher process
Returns {:ok, pid}.
Acquires an advisory lock on lock_path, runs fun, then releases it.
Retries on EEXIST until timeout. Returns {:error, :timeout} if the
lock cannot be acquired within the deadline.
Options
:timeout_ms— how long to wait in ms (default:5_000):retry_ms— poll interval in ms (default:100)
Creates a temporary directory, yields its path to fun, then deletes it.
The directory is deleted even when fun raises.
Creates a temporary file, yields its path to fun, then deletes it.
The file is deleted even when fun raises.
Options
:suffix— file extension suffix (default:""):dir— parent directory (default:System.tmp_dir!/0)
Writes text to a file, creating parent directories as needed.