On this page
  1. tecs.io.files
  2. Module contents
    1. Types
    2. Functions
  3. Types
    1. DirectoryEntry
    2. DirectoryStream
    3. File
    4. FileMode
    5. GlobOptions
    6. Info
    7. LineIterator
    8. PathInput
    9. PathType
    10. SymlinkKind
    11. TemporaryOptions
    12. TemporaryPath
    13. UserFolder
  4. Functions
    1. assetPath
    2. assetRoot
    3. basePath
    4. cachePath
    5. copy
    6. createDirectory
    7. createSymlink
    8. createTemporaryDirectory
    9. createTemporaryFile
    10. currentDirectory
    11. exists
    12. glob
    13. info
    14. isDirectory
    15. isFile
    16. isSymlink
    17. lines
    18. load
    19. open
    20. preferenceIdentity
    21. preferencePath
    22. read
    23. readLink
    24. remove
    25. rename
    26. setAssetRoot
    27. setPreferenceIdentity
    28. setReadOnly
    29. userFolder
    30. writablePath
    31. write
    32. writeAtomic
    33. writeAtomicAsync

tecs.io.files

Resolves game paths and performs complete filesystem operations.

Use assetPath for shipped content, writablePath for persistent mutable state, and cachePath for data the application can reconstruct. Set the publisher and game names before resolving the first writable path:

local files <const> = tecs.io.files
files.setPreferenceIdentity("Ex Nihilo", "Starfarer")

local directory <const> = files.writablePath("saves")
local ok, reason = files.createDirectory(directory)
if not ok then
    error(reason)
end

local path <const> = files.writablePath("saves/slot1.json")
local bytes <const> = tecs.data.encodeJSON({level = 3, hp = 100})
ok, reason = files.writeAtomic(path, bytes)
if not ok then
    error(reason)
end

Filesystem outcomes return a status and a platform reason. Invalid arguments raise because they indicate a defect in the calling program. Operations are synchronous except writeAtomicAsync, whose worker-backed future is advanced by tecs.runtime.poll. glob exposes a caller-owned pull stream so recursive enumeration does not retain a complete tree. Temporary files, temporary directories, and streams are Closeable and fit directly in tecs.scoped.

Every operation that accepts a filesystem location accepts either a string or an immutable Path. String results remain useful at Lua and platform boundaries; wrap one with tecs.io.Path.new when the next operation benefits from component-aware manipulation.

tecs.io.watcher polls paths recorded by read and the built-in asset loaders. It does not walk the whole asset tree.

open uses the standard Lua modes and returns one seekable file cursor. The SDL backend operates on the file directly. A storage backend without random access falls back to its required whole-file operations and retains the bytes until the file closes.

Module contents

Types

Type Kind Description
DirectoryEntry record DirectoryEntry describes one streamed child.
DirectoryStream record DirectoryStream is a caller-owned pull cursor over directory entries.
File interface File is the seekable cursor returned by open.
FileMode enum FileMode selects standard read, write, append, or update behavior.
GlobOptions record GlobOptions controls pattern matching and traversal depth.
Info record Info describes one resolved path.
LineIterator type LineIterator yields each line in a file and returns nil at the end.
PathInput type PathInput accepts either a platform path string or an immutable path object.
PathType enum PathType identifies a file, directory or other platform object after following symbolic links.
SymlinkKind enum SymlinkKind selects a file or directory symbolic link.
TemporaryOptions record TemporaryOptions selects generated-name details.
TemporaryPath record TemporaryPath owns an automatically removed file or directory.
UserFolder enum UserFolder identifies a well-known platform folder.

Functions

Function Kind Description
assetPath Static Resolves relative against the asset root.
assetRoot Static Returns the root from which the engine reads content.
basePath Static Returns the directory that contains the executable.
cachePath Static Returns the system cache directory for this application and creates it if absent.
copy Static Copies the file at from to to, replacing whatever was at to.
createDirectory Static Creates path, and any parents it needs.
createSymlink Static Creates a symbolic link to a file or directory.
createTemporaryDirectory Static Creates an empty temporary directory owned by the returned resource.
createTemporaryFile Static Creates an empty temporary file owned by the returned resource.
currentDirectory Static Returns the process working directory.
exists Static Returns whether anything occupies path.
glob Static Opens a pull stream over entries under path that match pattern.
info Static Returns information about path, or nil when nothing occupies it.
isDirectory Static Returns whether path resolves to a directory.
isFile Static Returns whether path resolves to a regular file.
isSymlink Static Returns whether the final object named by path is a symbolic link.
lines Static Iterates over the lines in a whole file.
load Static Compiles a Lua file without running it.
open Static Opens a file through one seekable cursor.
preferenceIdentity Static Returns the publisher and game names used for writable user data.
preferencePath Static Returns the writable directory for this application and creates it if absent.
read Static Reads a whole file and returns its bytes, or nil when there is none there.
readLink Static Returns the target spelling stored in a symbolic link.
remove Static Removes a file, or an empty directory.
rename Static Moves from to to, replacing whatever was at to.
setAssetRoot Static Overrides the asset root, for a test or a tool.
setPreferenceIdentity Static Sets the publisher and game names used for writable user data.
setReadOnly Static Changes the portable read-only state of a path.
userFolder Static Returns one of the platform's well-known folders.
writablePath Static Resolves relative against the writable root.
write Static Writes bytes to path, replacing whatever was there.
writeAtomic Static Durably writes bytes and atomically replaces path.
writeAtomicAsync Static Durably and atomically writes a complete file on a worker.

Types

tecs.io.files.DirectoryEntry record

DirectoryEntry describes one streamed child.

record tecs.io.files.DirectoryEntry
    path: Path
    name: string
    kind: storagebackend.PathType
    depth: integer
    symlink: boolean
end

tecs.io.files.DirectoryEntry.path field

Read-only. Contains the complete immutable path to this entry.

tecs.io.files.DirectoryEntry.path: Path

tecs.io.files.DirectoryEntry.name field

Read-only. Contains the entry name relative to its immediate parent.

tecs.io.files.DirectoryEntry.name: string

tecs.io.files.DirectoryEntry.kind field

Read-only. Identifies the resolved object's kind.

tecs.io.files.DirectoryEntry.kind: storagebackend.PathType

tecs.io.files.DirectoryEntry.depth field

Read-only. Reports one for an immediate child and increases during a recursive glob.

tecs.io.files.DirectoryEntry.depth: integer

Read-only. Reports whether the final path itself is a symbolic link.

tecs.io.files.DirectoryEntry.symlink: boolean

tecs.io.files.DirectoryStream record

DirectoryStream is a caller-owned pull cursor over directory entries.

record tecs.io.files.DirectoryStream is Closeable
    close: function(self): boolean, string
    next: function(self): DirectoryEntry, string
    skipDirectory: function(self): boolean
    toArray: function(self): {DirectoryEntry}, string
end

Interfaces

Interface
Closeable

tecs.io.files.DirectoryStream:close Instance

function tecs.io.files.DirectoryStream.close(self): boolean, string
Arguments
Name Type Description
self DirectoryStream
Returns
Type Description
boolean
string

tecs.io.files.DirectoryStream:next Instance

Returns the next entry.

function tecs.io.files.DirectoryStream.next(
    self
): DirectoryEntry, string
Arguments
Name Type Description
self DirectoryStream The open stream to advance.
Returns
Type Description
DirectoryEntry Returns the next entry, or nil at the end or after close.
string Returns a platform reason when traversal fails. Nil means end of stream.

tecs.io.files.DirectoryStream:skipDirectory Instance

Prevents descent into the directory returned by the preceding next call.

The method returns false when the preceding entry was not a directory, was a symbolic link, had no deeper pattern component, or has already been skipped. Calling next first makes an earlier directory no longer eligible for pruning.

function tecs.io.files.DirectoryStream.skipDirectory(self): boolean
Arguments
Name Type Description
self DirectoryStream The open stream whose pending descent the caller controls.
Returns
Type Description
boolean Returns whether a pending directory descent was removed.

tecs.io.files.DirectoryStream:toArray Instance

Consumes the remaining entries into an array and closes the stream.

Entries returned by earlier next calls are not repeated. A traversal failure discards the partial array and closes the stream.

function tecs.io.files.DirectoryStream.toArray(
    self
): {DirectoryEntry}, string
Arguments
Name Type Description
self DirectoryStream The open stream to consume.
Returns
Type Description
{DirectoryEntry} Returns every remaining entry, or nil when traversal fails.
string Returns the platform reason when the first return is nil.

tecs.io.files.File interface

File is the seekable cursor returned by open.

interface tecs.io.files.File is types.SeekableReader, types.SeekableWriter
end

Interfaces

Interface
types.SeekableReader
types.SeekableWriter

tecs.io.files.FileMode enum

FileMode selects standard read, write, append, or update behavior.

enum tecs.io.files.FileMode
    "a"
    "a+"
    "r"
    "r+"
    "w"
    "w+"
end

tecs.io.files.GlobOptions record

GlobOptions controls pattern matching and traversal depth.

record tecs.io.files.GlobOptions
    caseInsensitive: boolean
    maxDepth: integer
end

tecs.io.files.GlobOptions.caseInsensitive field

Caller-writable. Matches ASCII letters without regard to case when true. Defaults to false, which compares every UTF-8 codepoint exactly on every platform including the ones whose filesystem is not.

tecs.io.files.GlobOptions.caseInsensitive: boolean

tecs.io.files.GlobOptions.maxDepth field

Caller-writable. Limits traversal to this many levels below the root. Zero yields no entries, one yields immediate children, and nil permits unlimited traversal. Defaults to nil.

tecs.io.files.GlobOptions.maxDepth: integer

tecs.io.files.Info record

Info describes one resolved path.

record tecs.io.files.Info
    kind: PathType
    size: integer
    createdAt: number
    modifiedAt: number
    accessedAt: number
    readOnly: boolean
end

tecs.io.files.Info.kind field

Read-only. Identifies the resolved platform object's kind.

tecs.io.files.Info.kind: PathType

tecs.io.files.Info.size field

Read-only. Reports size in bytes. Zero for a directory.

tecs.io.files.Info.size: integer

tecs.io.files.Info.createdAt field

Read-only. Reports nanoseconds since the epoch as a double. Zero means the platform or filesystem does not record a creation time.

tecs.io.files.Info.createdAt: number

tecs.io.files.Info.modifiedAt field

Read-only. Reports modification time in nanoseconds since the epoch.

tecs.io.files.Info.modifiedAt: number

tecs.io.files.Info.accessedAt field

Read-only. Reports access time in nanoseconds since the epoch.

tecs.io.files.Info.accessedAt: number

tecs.io.files.Info.readOnly field

Read-only. Reports the portable read-only state of the resolved path.

tecs.io.files.Info.readOnly: boolean

tecs.io.files.LineIterator type

LineIterator yields each line in a file and returns nil at the end.

type tecs.io.files.LineIterator = function(): string

tecs.io.files.PathInput type

PathInput accepts either a platform path string or an immutable path object.

type tecs.io.files.PathInput = string | Path

tecs.io.files.PathType enum

PathType identifies a file, directory or other platform object after following symbolic links.

enum tecs.io.files.PathType
    "directory"
    "file"
    "other"
end

tecs.io.files.SymlinkKind enum

SymlinkKind selects a file or directory symbolic link.

enum tecs.io.files.SymlinkKind
    "directory"
    "file"
end

tecs.io.files.TemporaryOptions record

TemporaryOptions selects generated-name details.

record tecs.io.files.TemporaryOptions
    directory: string | Path
    prefix: string
    suffix: string
end

tecs.io.files.TemporaryOptions.directory field

Caller-writable. Selects the parent directory. Nil uses the operating system's temporary directory.

tecs.io.files.TemporaryOptions.directory: string | Path

tecs.io.files.TemporaryOptions.prefix field

Caller-writable. Prefixes the generated name. Defaults to "tecs-".

tecs.io.files.TemporaryOptions.prefix: string

tecs.io.files.TemporaryOptions.suffix field

Caller-writable. Suffixes the generated name. Defaults to an empty string.

tecs.io.files.TemporaryOptions.suffix: string

tecs.io.files.TemporaryPath record

TemporaryPath owns an automatically removed file or directory.

record tecs.io.files.TemporaryPath is Closeable
    path: Path

    close: function(self): boolean, string
    persist: function(self, destination: string | Path): boolean, string
end

Interfaces

Interface
Closeable

tecs.io.files.TemporaryPath.path field

Read-only. Contains the exclusively created path.

tecs.io.files.TemporaryPath.path: Path

tecs.io.files.TemporaryPath:close Instance

function tecs.io.files.TemporaryPath.close(self): boolean, string
Arguments
Name Type Description
self TemporaryPath
Returns
Type Description
boolean
string

tecs.io.files.TemporaryPath:persist Instance

Moves the resource to a permanent, absent destination and relinquishes cleanup.

function tecs.io.files.TemporaryPath.persist(
    self, destination: string | Path
): boolean, string
Arguments
Name Type Description
self TemporaryPath The open temporary resource.
destination string | Path The caller supplies a destination which must not exist.
Returns
Type Description
boolean Returns whether the resource became permanent.
string Returns the platform reason when the first return is false.

tecs.io.files.UserFolder enum

UserFolder identifies a well-known platform folder.

enum tecs.io.files.UserFolder
    "desktop"
    "documents"
    "downloads"
    "home"
    "music"
    "pictures"
    "publicShare"
    "savedGames"
    "screenshots"
    "templates"
    "videos"
end

Functions

tecs.io.files.assetPath Static

Resolves relative against the asset root.

function tecs.io.files.assetPath(relative: PathInput): string

Arguments

Name Type Description
relative PathInput The caller supplies a path under the content root with / separators. The function joins it without checking existence.

Returns

Type Description
string Returns the absolute path.

tecs.io.files.assetRoot Static

Returns the root from which the engine reads content.

function tecs.io.files.assetRoot(): string

Arguments

None.

Returns

Type Description
string Returns TECS_ASSETS when set, otherwise the host-configured root or basePath. The value stays cached until the platform changes.

tecs.io.files.basePath Static

Returns the directory that contains the executable.

function tecs.io.files.basePath(): string

Arguments

None.

Returns

Type Description
string Returns the directory with a trailing separator. It returns an empty string rather than nil when the platform declines to say, which is the case on some targets and is not an error: a caller falls back to a relative path.

tecs.io.files.cachePath Static

Returns the system cache directory for this application and creates it if absent.

The operating system may empty this directory between any two runs. Store only reconstructable downloads, compiled artifacts, thumbnails and similar derived data here. Saves, settings and other durable state belong under preferencePath.

function tecs.io.files.cachePath(): string

Arguments

None.

Returns

Type Description
string Returns the directory with a trailing platform separator, named from the preference identity.

tecs.io.files.copy Static

Copies the file at from to to, replacing whatever was at to.

The function refuses directories and requires an existing destination parent.

function tecs.io.files.copy(
    from: PathInput, to: PathInput
): boolean, string

Arguments

Name Type Description
from PathInput The caller supplies the existing source file.
to PathInput The caller supplies the destination file to replace.

Returns

Type Description
boolean Returns whether the platform copied the file.
string Returns the platform reason when the first return is false.

tecs.io.files.createDirectory Static

Creates path, and any parents it needs.

It succeeds when the directory already exists.

function tecs.io.files.createDirectory(path: PathInput): boolean, string

Arguments

Name Type Description
path PathInput The caller supplies the directory to create.

Returns

Type Description
boolean Returns whether the platform created or found the directory.
string Returns the platform reason when the first return is false.

Creates a symbolic link to a file or directory.

The target spelling is stored unchanged, so a relative target is resolved from the link's parent when later opened. kind is required because Windows must choose a file or directory link even for a dangling target.

function tecs.io.files.createSymlink(
    target: PathInput, link: PathInput, kind: SymlinkKind
): boolean, string
Name Type Description
target PathInput The caller supplies the target spelling to store.
link PathInput The caller supplies the new link path.
kind SymlinkKind The caller supplies "file" or "directory".
Type Description
boolean Returns whether the platform created the link.
string Returns the platform or unsupported reason when the first return is false.

tecs.io.files.createTemporaryDirectory Static

Creates an empty temporary directory owned by the returned resource.

Closing recursively removes its contents without following symbolic links. Call persist to keep the complete tree under an absent destination.

function tecs.io.files.createTemporaryDirectory(
    options: TemporaryOptions
): TemporaryPath, string

Arguments

Name Type Description
options TemporaryOptions The caller may select the parent, prefix, and suffix.

Returns

Type Description
TemporaryPath Returns the caller-owned temporary directory.
string Returns the platform or unsupported reason when creation fails.

tecs.io.files.createTemporaryFile Static

Creates an empty temporary file owned by the returned resource.

Creation is exclusive. Closing removes the file; garbage collection is a leak safety net, while tecs.scoped provides deterministic cleanup. Call persist to keep the file under an absent permanent destination.

function tecs.io.files.createTemporaryFile(
    options: TemporaryOptions
): TemporaryPath, string

Arguments

Name Type Description
options TemporaryOptions The caller may select the parent, prefix, and suffix.

Returns

Type Description
TemporaryPath Returns the caller-owned temporary file.
string Returns the platform or unsupported reason when creation fails.

tecs.io.files.currentDirectory Static

Returns the process working directory.

Command-line tools receive relative paths and resolve them against this directory. It is not where a game reads content from or writes state to: assetRoot, preferencePath and cachePath answer that, and say why. A platform with no working directory answers nil, which is most of the ones that are not a desktop.

function tecs.io.files.currentDirectory(): string, string

Arguments

None.

Returns

Type Description
string Returns the directory with a trailing separator, or nil when the platform has no working directory.
string Returns the platform reason when the first return is nil.

tecs.io.files.exists Static

Returns whether anything occupies path.

function tecs.io.files.exists(path: PathInput): boolean

Arguments

Name Type Description
path PathInput The caller supplies an absolute or platform-resolvable path.

Returns

Type Description
boolean Returns true when the platform finds any object.

tecs.io.files.glob Static

Opens a pull stream over entries under path that match pattern.

Recursive unless the pattern stops it: with no pattern this walks the whole tree below path. * and ? never match a separator, and ? consumes one UTF-8 codepoint, so "*" is one level, "*/*" is exactly two, and "*.png" matches only immediate children. Results include directories alongside files. Symbolic links are yielded but never followed. The order is the platform's own and is not sorted.

The stream retains only the unvisited names in each directory on its current descent. Close it when leaving early. After receiving a directory, call skipDirectory before next to prune that complete subtree. Call toArray to consume and close the stream when every remaining entry should be retained.

A fixed bound belongs in maxDepth; skipDirectory remains useful when descent depends on the entry itself. The checked example combines both.

function tecs.io.files.glob(
    path: PathInput, pattern: string, options: GlobOptions
): DirectoryStream, string

Arguments

Name Type Description
path PathInput The caller supplies the directory to enumerate.
pattern string The caller supplies /-separated * and ? wildcards, or nil to include every descendant recursively.
options GlobOptions The caller supplies matching and depth options, or omits them for case-sensitive, unlimited traversal.

Returns

Type Description
DirectoryStream Returns a caller-owned stream, or nil when enumeration cannot start.
string Returns the platform reason when the first return is nil.

Examples

local files <const> = tecs.io.files
tecs.scoped(function(scope: tecs.Scope)
    local stream, reason = files.glob(
        files.assetPath("levels"), nil, {maxDepth = 2}
    )
    if stream == nil then
        error(reason)
    end
    scope:own(stream)
    while true do
        local entry, nextReason = stream:next()
        if entry == nil then
            if nextReason ~= nil then
                error(nextReason)
            end
            break
        end
        print(entry.depth, entry.path)
        if entry.kind == "directory" and entry.name == "generated" then
            stream:skipDirectory()
        end
    end
end)

tecs.io.files.info Static

Returns information about path, or nil when nothing occupies it.

Nil is the answer for a path that does not exist, for a broken symbolic link, and when the platform cannot search a directory; the second return separates them.

function tecs.io.files.info(path: PathInput): Info, string

Arguments

Name Type Description
path PathInput The caller supplies an absolute or platform-resolvable path.

Returns

Type Description
Info Returns the path information, or nil when unavailable.
string Returns the platform reason when the first return is nil.

tecs.io.files.isDirectory Static

Returns whether path resolves to a directory.

function tecs.io.files.isDirectory(path: PathInput): boolean

Arguments

Name Type Description
path PathInput The caller supplies an absolute or platform-resolvable path.

Returns

Type Description
boolean Returns true when the resolved object is a directory.

tecs.io.files.isFile Static

Returns whether path resolves to a regular file.

function tecs.io.files.isFile(path: PathInput): boolean

Arguments

Name Type Description
path PathInput The caller supplies an absolute or platform-resolvable path.

Returns

Type Description
boolean Returns true when the resolved object is a regular file.

Returns whether the final object named by path is a symbolic link.

Unlike info, this function does not follow the final link. It does follow links in parent directories, so the result is path introspection and not a security boundary. A path that is absent or cannot be inspected returns false.

function tecs.io.files.isSymlink(path: PathInput): boolean
Name Type Description
path PathInput The caller supplies an absolute or platform-resolvable path.
Type Description
boolean Returns true when the final path itself is a symbolic link.

tecs.io.files.lines Static

Iterates over the lines in a whole file.

The function reads and closes the file before it returns the iterator, so breaking the loop retains only the immutable bytes and no file descriptor. It strips LF and CRLF terminators, returns empty lines between adjacent terminators, and does not invent another empty line after a final terminator. Use open when the input is too large to hold whole.

function tecs.io.files.lines(path: PathInput): LineIterator, string

Arguments

Name Type Description
path PathInput The caller supplies the source file.

Returns

Type Description
LineIterator Returns a LineIterator that yields each line in order, or nil when the platform cannot read the file.
string Returns the failure reason when the first return is nil.

Examples

local files <const> = require("tecs.io.files")
local nextLine <const> = assert(files.lines("save.txt"))

for line in nextLine do
    print(line)
end

tecs.io.files.load Static

Compiles a Lua file without running it.

The function reads through the installed storage backend rather than loadfile, records the source for file watching, and uses @path as the compiler's chunk name. The default environment is the caller's global environment. A supplied environment is installed exactly as given and is not a security boundary unless the caller makes it one.

function tecs.io.files.load(
    path: PathInput, environment: {string: any}
): function(...: any): any..., string

Arguments

Name Type Description
path PathInput The caller supplies the Lua source file.
environment {string : any} The caller supplies the globals visible when the chunk runs, or omits them to use the process globals.

Returns

Type Description
function(...: any): any... Returns the compiled chunk, or nil when reading or compilation fails. Calling the returned function executes the file.
string Returns the read or compiler reason when the first return is nil.

tecs.io.files.open Static

Opens a file through one seekable cursor.

The mode follows Lua's standard file modes. "r" opens an existing file for reading and is the default. "w" creates or truncates for writing. "a" creates or preserves for writes that always land at the end. Adding + permits both reading and writing. The cursor starts at byte zero except for "a"; "a+" starts at byte zero for reading while every write still lands at the current end. Seeks may not move past the end.

Close the file even after its last write succeeds. close flushes buffered bytes and can report a delayed storage failure. A backend without direct random access retains the complete file until close.

function tecs.io.files.open(
    path: PathInput, mode: FileMode
): File, string

Arguments

Name Type Description
path PathInput The caller supplies the file as a string or immutable Path.
mode FileMode The caller selects "r", "w", "a", "r+", "w+", or "a+", or omits it for "r".

Returns

Type Description
File Returns a caller-owned File, or nil when the platform cannot open it.
string Returns the platform reason when the first return is nil.

Examples

local files <const> = require("tecs.io.files")
local file, reason = files.open("world.pack", "w+")
if file == nil then
    error(reason)
end

local wrote, writeReason = file:write("HEADpayload bytes")
if not wrote then
    file:close()
    error(writeReason)
end
local position, seekReason = file:seek("start")
if position == nil then
    file:close()
    error(seekReason)
end
local header <const> = assert(file:read(4))
assert(header == "HEAD")

local closed, closeReason = file:close()
assert(closed, closeReason)

tecs.io.files.preferenceIdentity Static

Returns the publisher and game names used for writable user data.

The pair starts as "tecs", "tecs" and changes when setPreferenceIdentity succeeds.

function tecs.io.files.preferenceIdentity(): string, string

Arguments

None.

Returns

Type Description
string Returns the current publisher, studio, or organization name.
string Returns the current game or application name.

tecs.io.files.preferencePath Static

Returns the writable directory for this application and creates it if absent.

function tecs.io.files.preferencePath(): string

Arguments

None.

Returns

Type Description
string Returns the directory with a trailing separator, named from the preference identity. This is where a build writes durable state; cachePath is the other writable root and holds only reconstructable data.

tecs.io.files.read Static

Reads a whole file and returns its bytes, or nil when there is none there.

The binary string retains embedded NUL bytes. The synchronous call suits small documents; use tecs.assets.loadString when a whole-file read should run off the main thread, or its image and sound loaders for decoding.

function tecs.io.files.read(path: PathInput, kind: string): string

Arguments

Name Type Description
path PathInput The caller supplies an absolute path or one from assetPath.
kind string The caller supplies the content kind for watching, or omits it to record a document.

Returns

Type Description
string Returns the file bytes, or nil when the platform cannot read them.

Returns the target spelling stored in a symbolic link.

A relative target remains relative. The function does not resolve it against the link's parent and fails when path is not a symbolic link.

function tecs.io.files.readLink(path: PathInput): Path, string
Name Type Description
path PathInput The caller supplies the symbolic link to inspect.
Type Description
Path Returns the stored target as an immutable Path.
string Returns the platform or unsupported reason when the first return is nil.

tecs.io.files.remove Static

Removes a file, or an empty directory.

It does not recurse and fails on a directory with anything in it. It succeeds when there is nothing at path: the result says the path is gone, not that this call is what removed it.

Emptying a tree requires a glob and a deepest-first loop:

local stream = assert(files.glob(root)) local paths = {} while true do local entry, reason = stream:next() if entry == nil then if reason ~= nil then error(reason) end break end paths[#paths + 1] = entry.path end stream:close() table.sort(paths, function(a, b) return #(a:toString()) > #(b:toString()) end) for _, path in ipairs(paths) do files.remove(path) end files.remove(root)

function tecs.io.files.remove(path: PathInput): boolean, string

Arguments

Name Type Description
path PathInput The caller supplies the file or empty directory to remove.

Returns

Type Description
boolean Returns true when nothing remains at path.
string Returns the platform reason when the first return is false.

tecs.io.files.rename Static

Moves from to to, replacing whatever was at to.

Directories move as well as files, and an existing destination is overwritten with no warning and nothing to undo it. Whether this works across filesystems is the platform's business.

function tecs.io.files.rename(
    from: PathInput, to: PathInput
): boolean, string

Arguments

Name Type Description
from PathInput The caller supplies the existing source path.
to PathInput The caller supplies the destination path to replace.

Returns

Type Description
boolean Returns whether the platform moved the path.
string Returns the platform reason when the first return is false.

tecs.io.files.setAssetRoot Static

Overrides the asset root, for a test or a tool.

function tecs.io.files.setAssetRoot(root: PathInput)

Arguments

Name Type Description
root PathInput The caller supplies the new content directory. The function adds a trailing separator only when needed.

Returns

None.

tecs.io.files.setPreferenceIdentity Static

Sets the publisher and game names used for writable user data.

SDL combines these values with the current user and platform conventions to choose the directory returned by preferencePath. The defaults are "tecs" and "tecs". Later calls change which directory the next preferencePath, writablePath, or cachePath resolves.

function tecs.io.files.setPreferenceIdentity(
    organization: string, application: string
)

Arguments

Name Type Description
organization string The caller supplies a non-empty publisher, studio, or organization name.
application string The caller supplies a non-empty game or application name.

Returns

None.

tecs.io.files.setReadOnly Static

Changes the portable read-only state of a path.

On Unix, making a path read-only clears every write bit and making it writable restores only the owner's write bit. The API deliberately does not model platform ACLs, ownership, or executable bits.

function tecs.io.files.setReadOnly(
    path: PathInput, readOnly: boolean
): boolean, string

Arguments

Name Type Description
path PathInput The caller supplies the existing path to change.
readOnly boolean The caller supplies true to prevent ordinary writes.

Returns

Type Description
boolean Returns whether the platform changed the state.
string Returns the platform or unsupported reason when the first return is false.

tecs.io.files.userFolder Static

Returns one of the platform's well-known folders.

Often nil, and legitimately so. A platform that has no such concept says so rather than inventing a path: macOS has no saved-games, screenshots or templates folder and answers nil for all three, and a platform that is not a desktop may have none of them. Treat every one of these as absent until it is not, and never as a place a build may write; preferencePath and cachePath are the two writable roots, with different durability.

function tecs.io.files.userFolder(which: UserFolder): string, string

Arguments

Name Type Description
which UserFolder The caller supplies the well-known folder to resolve.

Returns

Type Description
string Returns the folder with a trailing separator, or nil when the platform has no matching folder.
string Returns the platform reason when the first return is nil.

tecs.io.files.writablePath Static

Resolves relative against the writable root.

function tecs.io.files.writablePath(relative: PathInput): string

Arguments

Name Type Description
relative PathInput The caller supplies a path under the preference directory.

Returns

Type Description
string Returns the absolute path.

tecs.io.files.write Static

Writes bytes to path, replacing whatever was there.

The string's length controls the binary write, so embedded NUL bytes remain data and an empty string creates an empty file. The parent directory must already exist.

function tecs.io.files.write(
    path: PathInput, bytes: string
): boolean, string

Arguments

Name Type Description
path PathInput The caller supplies the destination file.
bytes string The caller supplies the complete binary contents.

Returns

Type Description
boolean Returns whether the platform wrote the complete file.
string Returns the platform reason when the first return is false.

tecs.io.files.writeAtomic Static

Durably writes bytes and atomically replaces path.

The platform writes a uniquely named temporary file beside path, commits its complete contents to durable storage, atomically replaces the destination, and commits the containing directory where the operating system provides that operation. An existing destination remains untouched when anything fails before replacement, and no temporary file is retained.

A failure after replacement means the complete new file is visible but the platform could not confirm that the directory update will survive a power loss. The function returns false in that case rather than overstating durability. Hardware can still violate an operating system's completed flush request.

A storage backend without an atomic durable commit returns false and an unsupported reason. The function never falls back to write plus rename. The parent directory must already exist.

function tecs.io.files.writeAtomic(
    path: PathInput, bytes: ByteInput
): boolean, string

Arguments

Name Type Description
path PathInput The caller supplies the destination file.
bytes ByteInput The caller supplies a string or open Buffer or ByteView containing the complete binary contents. Buffers and views are borrowed only for this synchronous call and are not copied or closed.

Returns

Type Description
boolean Returns whether the platform confirmed the atomic durable write.
string Returns the platform or unsupported reason when the first return is false.

Examples

local save <const> = tecs.io.Path.new(
    tecs.io.files.writablePath("saves"), "slot1.bin"
)
local ok, reason = tecs.io.files.writeAtomic(save, "snapshot bytes")
if not ok then
    error(reason)
end

tecs.io.files.writeAtomicAsync Static

Durably and atomically writes a complete file on a worker.

The returned Future becomes ready with true after the same commit performed by writeAtomic, or fails with its platform reason. The call copies a buffer or byte view before returning, so the caller may mutate or close it immediately. String bytes cross the worker channel by value as well. tecs.runtime.poll advances the future each frame; Future:wait advances it in headless code.

Canceling the future stops interest in its result but cannot safely interrupt a filesystem commit already in progress. The shared worker exits automatically after its last queued result is drained. A non-SDL storage backend receives a failed future because a separate worker state cannot inherit the main state's installed Lua backend.

function tecs.io.files.writeAtomicAsync(
    path: PathInput, bytes: ByteInput
): Future<boolean>

Arguments

Name Type Description
path PathInput The caller supplies the destination file.
bytes ByteInput The caller supplies the complete binary contents.

Returns

Type Description
Future<boolean> Returns a future which becomes ready with true or fails.