Manual · API

# `files`

Folders, dialogs, reading and writing text — and the permissions macOS puts between an application and the disk.

Every command on this page carries a worked example.

###
chooseOpen function

`files.chooseOpen(options)`

The system's open dialog — a path, or `null` for Cancel.

Worked example

    const path = files.chooseOpen({ types: ["csv"] });
    if (path === null) { return; }   // Cancel

###
chooseSave function

`files.chooseSave(options)`

The system's save dialog — where to write, or `null`.

Worked example

    const target = files.chooseSave({ suggestedName: "Export.csv" });
    if (target !== null) {
        files.writeText(target, csvText);
    }

###
asset function

`files.asset(name) → file or null`

A file the project ships. Everything in the project's `assets` folder travels inside the application — **folders included**, and then the name is the path inside it: `letters/reminder.txt`. This hands it over as the same object a file field gives you — **by name, never by path**: in a built application there is no folder to point at, and the same call works in the designer and at your customer's. Read-only; write with `writeText` into `applicationFolder()`.

Worked example

    // A letter template that ships with the application:
    const template = files.asset("Reminder.txt");
    if (template) {
        form.body.value = template.text
            .replace("{name}", form.record.customer.name);
    }

###
assetNames function

`files.assetNames() → array of names`

Everything the project ships, sorted — for a script that offers a choice rather than knowing one.

Worked example

    // Every letter template the project carries:
    const templates = files.assetNames().filter(n => n.endsWith(".txt"));
    log(templates.length + " templates: " + templates.join(", "));
    form.body.value = files.asset(templates[0]).text;

###
applicationFolder function

`files.applicationFolder()`

The application's own folder under Application Support — always writable, no questions asked.

Worked example

    // The application's own notes file — writable without any dialog:
    const path = files.applicationFolder() + "/lastRun.txt";
    files.writeText(path, new Date().toISOString());

###
desktop function

`files.desktop()`

The user's desktop. macOS asks the user once, on first access — the rule surfaced honestly.

Worked example

    // macOS asks once, the first time — after that this just answers:
    files.writeText(files.desktop() + "/Report.txt", text);

###
documents function

`files.documents()`

The Documents folder — asks once on first access.

Worked example

    const folder = files.documents();

###
downloads function

`files.downloads()`

The Downloads folder — asks once on first access.

Worked example

    const newest = files.downloads() + "/prices.csv";
    if (files.canRead(newest)) { importPrices(newest); }

###
home function

`files.home()`

The user's home folder.

Worked example

    log(files.home());   // "/Users/anna"

###
temporary function

`files.temporary()`

A scratch folder that may vanish when the application quits — for intermediate files, never for data.

Worked example

    // Scratch space — may vanish when the application quits:
    const scratch = files.temporary() + "/preview.csv";

###
readText function

`files.readText(path, { encoding })`

The whole file as one text.

Run `detectEncoding` first on files you did not write — yesterday's exports are `windows1252` more often than anybody hopes, and a wrong guess turns umlauts to rubble.
Worked example

    const encoding = files.detectEncoding(path);
    const whole = files.readText(path, { encoding });

###
readLines function

`files.readLines(path, { encoding })`

The file as an array of lines — what a loop wants.

Worked example

    const path = files.chooseOpen();
    if (path !== null) {
        const encoding = files.detectEncoding(path);   // "windows1252"?
        for (const line of files.readLines(path, { encoding })) {
            log(line);
        }
    }

###
writeText function

`files.writeText(path, text, { encoding })`

Writes the text as the whole file.

Pair with `chooseSave` for user files; for the application's own, `applicationFolder()` never asks permission.
Worked example

    for (const line of files.readLines(path, { encoding: "utf8" })) {
        if (line.trim() === "") { continue; }
        handle(line.split(";"));
    }

###
detectEncoding function

`files.detectEncoding(path)`

What an old export really is — `"windows1252"` more often than anybody hopes. Hand the answer to `readText`.

Worked example

    files.writeText(target, lines.join("\n"), { encoding: "utf8" });

###
canRead function

`files.canRead(path)`

Tries, honestly — `true`/`false`.

Worked example

    const encoding = files.detectEncoding(path);   // "windows1252", "utf8", …
    const text = files.readText(path, { encoding });

###
canWrite function

`files.canWrite(path)`

Tries with a probe file — `true`/`false`.

Worked example

    if (!files.canRead(path)) {
        messages.showError("That file cannot be read.");
        return;
    }

###
openPermissionSettings function

`files.openPermissionSettings()`

The System Settings pane where a refused folder permission can be undone — so your error dialog can offer the way out.

Worked example

    if (!files.canWrite(folder)) {
        files.openPermissionSettings();
        return;
    }