Skip to content

File API

Declared by <huxerui/file.h>.

  • FileType: File, Directory, Other.
  • FileInfo: type, byte size, optional modification time.
  • IoErrorCode: NotFound, PermissionDenied, NotDirectory, IsDirectory, TooLarge, InvalidEncoding, Unsupported, Io, AlreadyExists, Timeout, NoSpace.
  • IoError: code and message.
  • IoResult<T>: construct from value/error; Succeeded, ref-qualified Value, and Error accessors.

Construct from UTF-8 path/string view or parent plus child. Path queries: Path, Name, Stem, Extension, ParentPath, Parent, Child, and Resolve. Status queries: Exists, IsFile, IsDirectory, synchronous/async Stat.

I/O methods have synchronous and Async forms: read bytes/string; write and append bytes/string; list children; create one/all directories; delete or recursively delete; copy; and move. Copy/move accept overwrite = false. Async methods return Task.

File::OpenRead() returns IoResult<InputStream>; OpenReadAsync() returns Task<IoResult<AsyncInputStream>>. Writers use OpenWrite(mode) or OpenWriteAsync(mode), with FileWriteMode::Truncate by default or Append. Opening a writer can create the file but not missing parent directories.

FileReference offers async read/write opening through its provider. Opening a writer replaces existing contents and requires writable ordinary-file access; it does not turn a read-only picker grant into a writable grant. Await CloseAsync() to finish output, especially for browser persistence and provider-backed staging. See Streams for EOF, operation ordering, and partial failures.

Capability for a selected or activated file. Metadata: Name, optional Size, optional ContentType, CanWrite. Async operations: ReadBytesAsync, ReadStringAsync, ImportToAsync, and ReplaceWithAsync.

FilePickerFilter contains name, extensions, and content types. SaveFileOptions contains suggested name and filter. Capability queries are CanOpenFiles and CanSaveFiles; operations are OpenFileAsync, OpenFilesAsync, and SaveFileAsync.

UseApplication().Directories() returns AppDirectories: an optional executable directory and data, cache, and temporary directories. UseApplication().CurrentDirectory() queries the process working directory at the time of the call. These paths do not create entries or grant access. Capture the ApplicationHandle during composition; its directory accessors can also run outside composition. Obtain the picker separately with UseService<FilePicker>().

Directory values are captured at initialization and can outlive the Runtime; the returned reference requires the handle or service to stay alive. Copy a File when retaining one path. Missing directory support throws std::logic_error; failure to query the working directory throws std::runtime_error.

#include <huxerui/huxerui.h>
using namespace huxerui;
Task<void> OpenText(std::shared_ptr<FilePicker> picker, State<std::string> content) {
auto selected = co_await picker->OpenFileAsync({
.name = "Text",
.extensions = {"txt"},
.content_types = {"text/plain"},
});
if (!selected) {
co_return;
}
auto text = co_await selected->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));
});
}

Resolve services and task scope during composition before capturing them in an event. An empty optional means no file was delivered: cancellation, denial, failure, and an unsupported host are not distinguished by this result. A returned FileReference preserves provider authority without inventing a local path.

FilePicker::CanOpenDirectories(writable = false) checks the requested kind of directory access; OpenDirectoryAsync(writable = false) returns an optional FileReference. User cancellation is empty, not a directory with an empty path.

FileReference::Type() describes the captured entry kind. For a directory, ListChildrenAsync(), CreateDirectoryAsync(name), and CopyFileFromAsync(source, name, overwrite = false) operate through its retained provider grant. CopyDirectoryContentsToAsync(destination, overwrite = false) accepts a File or FileReference destination and returns IoResult<DirectoryCopySummary>. This is not a transaction: failure/cancellation can leave already copied output; success counts are meaningful only after successful completion.

AsFile() returns an optional local File when the provider has a known path. It neither imports data nor transfers the reference’s grant. Keep the FileReference alive while using a path that depends on its access/temporary-file ownership. Android document URIs and browser handles do not become local paths. File::ToUri() converts a local path to a URI; it does not manufacture provider authority.

Treat display names, captured MIME metadata, and sizes as potentially stale/untrusted. A writable directory grant does not promise every existing child can be overwritten.

Declared by <huxerui/file_drop.h>. FileDropTarget::Accepts(FileDropOptions[, predicate]) receives ordinary files from the host drag system with Copy effect only.

#include <huxerui/huxerui.h>
#include <string>
#include <vector>
using namespace huxerui;
View FileDropArea(State<std::string> status) {
return Text("Drop text files here")
.With(Padding(24.0F), FileDropTarget::Accepts({.extensions = {"txt"}}))
.On<FileDropEvents::Dropped>([status](const std::vector<FileReference>& files, const FileDropEvent&) {
status = "Received " + std::to_string(files.size()) + " files";
})
.On<FileDropEvents::Failed>([status](const IoError& error, const FileDropEvent&) {
status = error.message;
});
}

extensions and content_types are alternative filters; every file must pass before delivery. allows_multiple = false rejects a multiple-file batch in full. Metadata predicates must be quick and side-effect-free; unknown hover metadata is not proof of final acceptance.

Entered/Moved/Exited report hover; Exited also occurs at physical drop and does not imply cancellation. Deferred Dropped delivers a complete batch after validation; Failed reports preparation failure without partial delivery. Handlers run on the UI thread and do not run after unmount. Copy FileReference values if retaining them beyond a handler.

A drop does not read/import the content or grant write permission. Always provide an equivalent FilePicker button for touch, keyboard, accessibility, and unsupported hosts. Use DragSource/DropTarget for typed in-process transfers.

File stores an absolute, lexically normalized path; Path() uses UTF-8 with forward slashes. Construction, Child, Resolve, Parent, and ToUri do not create/open an entry or grant permission. Child(name) accepts one nonempty segment, rejecting . and ..; Resolve(relative_path) accepts multiple segments and can escape the base with ... Neither is a symbolic-link containment check for untrusted input.

Exists, IsFile, and IsDirectory collapse query failures to false. Use Stat/StatAsync when an error category matters. Metadata is best-effort and can change before the next operation; an existence check is not protection from a race.

ReadBytes/ReadString return IoResult<T>; an empty file is successful empty data. Text reads validate UTF-8, strip one leading UTF-8 BOM, and preserve newlines. Binary data, UTF-16, or a legacy encoding should not be fed to ReadString and treated as an empty document on error.

Write/append operations return bool, not IoResult. A write creates or truncates the target, requires an existing parent, and is not atomic. Failure/cancellation may leave partial output. Async inputs are owned by the Task; synchronous spans/views are borrowed only for the call. Prefer asynchronous operations from UI work, and use them for Web persistent paths where persistence requires the async path.

FilePicker::SaveFileAsync(source, options) exports an existing local file; it does not return a writable destination path. Prepare the source first, then show the picker. The source remains in place. A false result is not enough to claim the user explicitly canceled.

#include <huxerui/huxerui.h>
#include <memory>
#include <string>
using namespace huxerui;
Task<void> ExportText(std::shared_ptr<FilePicker> picker, File prepared, std::string text,
State<std::string> status) {
if (!picker->CanSaveFiles()) {
status = "Export is unavailable on this host";
co_return;
}
if (!co_await prepared.WriteStringAsync(text)) {
status = "Could not prepare the export";
co_return;
}
const bool exported = co_await picker->SaveFileAsync(prepared, {
.suggested_name = "notes.txt",
.filter = {.name = "Text", .extensions = {"txt"}, .content_types = {"text/plain"}},
});
status = exported ? "Exported" : "No export completed";
}

The caller supplies an application-owned temporary File with an existing parent and launches this task through its TaskScope. Give concurrent exports different temporary paths and clean them up through their owning storage policy. Do not delete the prepared file before the picker finishes or assume a canceled write rolled back.

ImportToAsync copies a provider file into local storage; ReplaceWithAsync writes an existing writable provider reference from a local source. These are distinct from picking a new destination. Keep the FileReference alive for as long as its provider grant or temporary ownership is needed.