On this page
- tecs.io.files
Functions
- assetPath
- assetRoot
- basePath
- cachePath
- copy
- createDirectory
- createSymlink
- createTemporaryDirectory
- createTemporaryFile
- currentDirectory
- exists
- glob
- info
- isDirectory
- isFile
- isSymlink
- lines
- load
- open
- preferenceIdentity
- preferencePath
- read
- readLink
- remove
- rename
- setAssetRoot
- setPreferenceIdentity
- setReadOnly
- userFolder
- writablePath
- write
- writeAtomic
- 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)
endFilesystem 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
endtecs.io.files.DirectoryEntry.path field
Read-only. Contains the complete immutable path to this entry.
tecs.io.files.DirectoryEntry.path: Pathtecs.io.files.DirectoryEntry.name field
Read-only. Contains the entry name relative to its immediate parent.
tecs.io.files.DirectoryEntry.name: stringtecs.io.files.DirectoryEntry.kind field
Read-only. Identifies the resolved object's kind.
tecs.io.files.DirectoryEntry.kind: storagebackend.PathTypetecs.io.files.DirectoryEntry.depth field
Read-only. Reports one for an immediate child and increases during a recursive glob.
tecs.io.files.DirectoryEntry.depth: integertecs.io.files.DirectoryEntry.symlink field
Read-only. Reports whether the final path itself is a symbolic link.
tecs.io.files.DirectoryEntry.symlink: booleantecs.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
endInterfaces
| Interface |
|---|
Closeable |
tecs.io.files.DirectoryStream:close Instance
function tecs.io.files.DirectoryStream.close(self): boolean, stringArguments
| 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, stringArguments
| 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): booleanArguments
| 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}, stringArguments
| 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
endInterfaces
| 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+"
endtecs.io.files.GlobOptions record
GlobOptions controls pattern matching and traversal depth.
record tecs.io.files.GlobOptions
caseInsensitive: boolean
maxDepth: integer
endtecs.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: booleantecs.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: integertecs.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
endtecs.io.files.Info.kind field
Read-only. Identifies the resolved platform object's kind.
tecs.io.files.Info.size field
Read-only. Reports size in bytes. Zero for a directory.
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.modifiedAt field
Read-only. Reports modification time in nanoseconds since the epoch.
tecs.io.files.Info.modifiedAt: numbertecs.io.files.Info.accessedAt field
Read-only. Reports access time in nanoseconds since the epoch.
tecs.io.files.Info.accessedAt: numbertecs.io.files.Info.readOnly field
Read-only. Reports the portable read-only state of the resolved path.
tecs.io.files.LineIterator type
LineIterator yields each line in a file and returns nil at the end.
type tecs.io.files.LineIterator = function(): stringtecs.io.files.PathInput type
PathInput accepts either a platform path string or an immutable path object.
type tecs.io.files.PathInput = string | Pathtecs.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"
endtecs.io.files.SymlinkKind enum
SymlinkKind selects a file or directory symbolic link.
enum tecs.io.files.SymlinkKind
"directory"
"file"
endtecs.io.files.TemporaryOptions record
TemporaryOptions selects generated-name details.
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 | Pathtecs.io.files.TemporaryOptions.prefix field
Caller-writable. Prefixes the generated name. Defaults to "tecs-".
tecs.io.files.TemporaryOptions.prefix: stringtecs.io.files.TemporaryOptions.suffix field
Caller-writable. Suffixes the generated name. Defaults to an empty string.
tecs.io.files.TemporaryOptions.suffix: stringtecs.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
endInterfaces
| Interface |
|---|
Closeable |
tecs.io.files.TemporaryPath.path field
Read-only. Contains the exclusively created path.
tecs.io.files.TemporaryPath.path: Pathtecs.io.files.TemporaryPath:close Instance
function tecs.io.files.TemporaryPath.close(self): boolean, stringArguments
| 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, stringArguments
| 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"
endFunctions
tecs.io.files.assetPath Static
Resolves relative against the asset root.
function tecs.io.files.assetPath(relative: PathInput): stringArguments
| 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(): stringArguments
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(): stringArguments
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(): stringArguments
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.
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, stringArguments
| 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. |
tecs.io.files.createSymlink Static
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, stringArguments
| 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". |
Returns
| 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, stringArguments
| 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, stringArguments
| 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, stringArguments
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): booleanArguments
| 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, stringArguments
| 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.
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): booleanArguments
| 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): booleanArguments
| 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. |
tecs.io.files.isSymlink Static
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): booleanArguments
| Name | Type | Description |
|---|---|---|
path |
PathInput |
The caller supplies an absolute or platform-resolvable path. |
Returns
| 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, stringArguments
| 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)
endtecs.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..., stringArguments
| 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.
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, stringArguments
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(): stringArguments
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): stringArguments
| 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. |
tecs.io.files.readLink Static
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.
Arguments
| Name | Type | Description |
|---|---|---|
path |
PathInput |
The caller supplies the symbolic link to inspect. |
Returns
| 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, stringArguments
| 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.
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, stringArguments
| 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, stringArguments
| 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): stringArguments
| 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, stringArguments
| 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.
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)
endtecs.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.
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. |