FileHandler
Open a file and work on part of it: read a range of bytes, insert at any point, append at the end.
PathHandler:OpenAsync() gives one, a child of FileService, making a missing file first. Ranges are 1-based and inclusive, like string.sub, and WriteAsync inserts like table.insert: index 1 is the start, Length + 1 the end. Length is as this handler last saw it. Destroy() closes it, and any member after that errors. Today each ranged call reads the whole file underneath.
Example
-- Writes a log, opens it, reads a byte range, appends a line and reads the new part. Ranges are 1-based and inclusive.
use FileService
FileService:WriteAsync("app.log", "started\nloaded Notes\n")
local log, why = FileService:GetPathHandler("app.log"):OpenAsync()
if not log then
error("couldn't open app.log: " .. tostring(why))
end
print("Length " .. log.Length)
print("bytes 9 to 14: " .. tostring((log:ReadStringAsync(9, 14))))
log:AppendAsync("saved todo.txt\n")
print("Length after AppendAsync " .. log.Length)
print("bytes 22 to 35: " .. tostring((log:ReadStringAsync(22, 35))))
log:WriteAsync("[app] ", 1)
print("bytes 1 to 13 after WriteAsync at 1: " .. tostring((log:ReadStringAsync(1, 13))))
print("a child of FileService: " .. tostring(log.Parent == FileService))
log:Destroy()
FileService:RemoveAsync("app.log")Length 21 bytes 9 to 14: loaded Length after AppendAsync 36 bytes 22 to 35: saved todo.txt bytes 1 to 13 after WriteAsync at 1: [app] started a child of FileService: true

Properties
| Name | Type | Default | Description |
|---|---|---|---|
| Length | number | 0 read-only | The file's length in bytes as this handler last saw it: at OpenAsync and after its own reads and writes, not others' changes. |
Methods
| Name | Arguments | Returns | Description |
|---|---|---|---|
| AppendAsync yields | (content: string | buffer) | (boolean, string?) | Waits to add content, a string or a buffer, at the file's end as it is now. |
| ReadBufferAsync yields | (start: number, finish: number) | (buffer?, string?) | Waits to read bytes start to finish into a buffer, 1-based and inclusive like ReadStringAsync. |
| ReadStringAsync yields | (start: number, finish: number) | (string?, string?) | Waits to read bytes start to finish, 1-based and inclusive; past the end gives what is there, and start must be at least 1. |
| WriteAsync yields | (content: string | buffer, index: number) | (boolean, string?) | Waits to insert content at index, table.insert style: 1 puts it at the start, Length + 1 at the end; other indexes error. |
From ShotInstance 33
ClassNameNameParentAncestryChangedAttributeChangedChangedChildAddedChildRemovedDestroyingAddTagClearAllChildrenCloneDestroyFindFirstAncestorFindFirstAncestorOfClassFindFirstAncestorWhichIsAFindFirstChildFindFirstChildOfClassFindFirstChildWhichIsAGetAttributeGetAttributeChangedSignalGetAttributesGetChildrenGetDescendantsGetFullNameGetPropertyChangedSignalGetTagsHasTagIsAIsAncestorOfIsDescendantOfRemoveTagSetAttribute
