Files
UseApplication() provides application directories; File performs local path operations.
FilePicker returns capability-bearing FileReference values instead of assuming every platform exposes a durable filesystem path.
Open a user-selected file
Section titled “Open a user-selected file”Task<void> OpenText(std::shared_ptr<FilePicker> picker, State<std::string> content) { auto picked = co_await picker->OpenFileAsync({ .name = "Text", .extensions = {"txt"}, }); if (picked) { auto text = co_await picked->ReadStringAsync(); if (text.Succeeded()) { content = std::move(text).Value(); } }}
[[huxerui::composable]]View OpenTextButton(State<std::string> content) { auto picker = UseService<FilePicker>(); auto tasks = UseTaskScope(); return Button("Open text file").OnClick([picker, tasks, content] { tasks.Launch(OpenText(picker, content)); });}An empty optional means the user cancelled the picker. It is not a framework error and should not produce an error message. Resolve the picker and task scope during composition; the event captures stable handles rather than consulting composition context from inside a coroutine.
Keep provider authority
Section titled “Keep provider authority”Use FileReference for user-selected and externally activated files.
It carries metadata and platform authority and supports reading, importing, and replacement when writable without pretending that every provider value is a durable local path.
Retain the reference only for as long as its platform contract permits. Import content into application storage when the application needs durable ownership.
A reference is not a path string.
On Android it may represent a document-provider URI, on Apple a security-scoped or picker-provided object, and on Web a browser file capability.
Use Name, Size, and ContentType as hints; validate the bytes you actually read.
An edit workflow normally keeps the original reference while the document is open, writes an application-owned temporary file, then calls ReplaceWithAsync only when CanWrite() is true.
If replacement is unavailable, offer SaveFileAsync and let the platform picker choose a destination.
Work with application files
Section titled “Work with application files”Use File for application-owned paths.
AppDirectories identifies platform-resolved executable (when available), data, cache, and temporary locations according to the current adapter.
Obtain directories with UseApplication().Directories() and the picker with UseService<FilePicker>(). A captured ApplicationHandle can query directories outside composition; path values themselves do not perform I/O.
File offers synchronous operations for code that already runs off the UI thread and Async counterparts for component-owned work.
Read, stat, and listing operations return IoResult<T>; mutation methods report success with bool.
Inspect Succeeded() before taking Value(), and use IoErrorCode to choose a recoverable application response.
Synchronous methods are appropriate only when the caller is already off the UI thread and the platform exposes a synchronous path.
Component event handlers should use the Async forms through TaskScope; blocking the UI thread can stall rendering, input, and native picker completion.
Treat data, cache, and temporary directories differently. User documents do not become durable merely because they were copied to cache, and temporary files may disappear between sessions. Use the data directory for application-owned persistent state and keep user-facing export in the picker workflow.
Incremental I/O
Section titled “Incremental I/O”For large files, open File::OpenReadAsync() or FileReference::OpenReadAsync() and await ReadAsync(maximum_bytes) on the returned stream. A successful empty buffer is EOF; a short nonempty chunk is not. The shared stream API also works with raw resources and HTTP bodies.
To copy without retaining the entire document, open an async writer, await CopyToAsync(writer, 64 * 1024), then await writer.CloseAsync(). Neither a successful write nor copy finalizes the destination. Preserve endpoint handles until their tasks finish, and allow only one pending operation per stream. Failure or cancellation can leave partial output.
See the complete file-copy example.
Filter and save
Section titled “Filter and save”Picker filters describe names, extensions, and MIME intent where supported. They improve the platform picker experience but are not a security boundary; validate content after opening it.
Use the save picker for a new destination and the replacement operations on a writable FileReference when updating an existing user-selected document.
Map errors deliberately:
| Result | Typical application response |
|---|---|
| Empty picker optional | No file was delivered; do not infer whether this was cancellation, denial, failure, or lack of support |
PermissionDenied |
Explain what operation needs permission and offer another file |
TooLarge |
Keep the current document and report the accepted limit |
InvalidEncoding |
Offer binary/import handling instead of displaying corrupt text |
Unsupported |
Hide or disable the unavailable workflow when capability queries allow it |
Io |
Preserve the user’s current state and offer retry or another destination |
See the File API for exact overloads and result types, and Lifecycle and activation for files delivered when another application opens content with HuxerUI.
Work with a selected directory
Section titled “Work with a selected directory”Check CanOpenDirectories(writable), then await OpenDirectoryAsync(writable). A directory is still a FileReference, not automatically a File path. Use its ListChildrenAsync, CreateDirectoryAsync, and CopyFileFromAsync methods to preserve provider access.
CopyDirectoryContentsToAsync recursively copies into a File or FileReference destination. It is not atomic: cancellation/failure can leave partial output. Confirm overwrite intent in the UI and report the returned error instead of claiming rollback.
Use AsFile() only when a path-based integration really needs a local path. Retain the original FileReference for the duration of grant-dependent path access. Provider names are display metadata, not trusted path fragments.
For OS drag reception, use FileDropTarget and the same FileReference processing code as your picker/activation handlers. Keep a picker button available for users who cannot drag.

