← Back to Documentation

File System

ARO provides built-in file system operations for reading, writing, and watching files. This chapter covers file I/O and directory monitoring.

Reading Files

Text Files

<Read> the <content> from the <file: "./data.txt">.
<Read> the <readme> from the <file: "./README.md">.

JSON Files

<Read> the <config: JSON> from the <file: "./config.json">.
<Read> the <data: JSON> from the <file: "./data.json">.

Binary Files

<Read> the <image: bytes> from the <file: "./logo.png">.
<Read> the <document: bytes> from the <file: "./report.pdf">.

Dynamic Paths

(GET /files/{name}: File API) {
    <Extract> the <filename> from the <request: parameters>.
    <Read> the <content> from the <file: "./uploads/${filename}">.
    <Return> an <OK: status> with <content>.
}

Error Handling

(Load Config: Configuration) {
    <Read> the <config: JSON> from the <file: "./config.json">.

    if <config> is empty then {
        <Log> the <warning> for the <console> with "Config not found, using defaults".
        <Create> the <config> with {
            port: 8080,
            debug: false
        }.
    }

    <Publish> as <app-config> <config>.
    <Return> an <OK: status> for the <loading>.
}

Writing Files

Text Files

<Write> the <content> to the <file: "./output.txt">.
<Write> the <report> to the <file: "./reports/daily.txt">.

JSON Files

<Write> the <config: JSON> to the <file: "./config.json">.
<Write> the <data: JSON> to the <file: "./export.json">.

Appending

<Store> the <log-entry> into the <file: "./logs/app.log">.
<Store> the <record> into the <file: "./data/records.csv">.

Creating Directories

Directories are created automatically when writing:

(* ./reports/2024/01/ is created if it doesn't exist *)
<Write> the <report> to the <file: "./reports/2024/01/daily.txt">.

Deleting Files

<Delete> the <file: "./temp/cache.json">.
<Delete> the <file: path>.

File Watching

Starting a Watcher

Watch directories for changes using the <Watch> action:

(Application-Start: File Processor) {
    <Log> the <startup: message> for the <console> with "Starting file processor".

    (* Watch the inbox directory for new files *)
    <Watch> the <file-monitor> for the <directory> with "./inbox".

    (* Keep running until shutdown *)
    <Keepalive> the <application> for the <events>.

    <Return> an <OK: status> for the <startup>.
}

Watch Syntax:

<Watch> the <file-monitor> for the <directory> with "path".

The <Watch> action:

File Events

Watchers emit events when files change:

Event When Triggered Data
FileCreatedEvent New file created path - file path
FileModifiedEvent Existing file modified path - file path
FileDeletedEvent File deleted path - file path

Event Handler Naming Convention

Feature sets with business activity File Event Handler receive file events. The feature set name determines which event type it handles:

Feature Set Name Handles Event
Handle File Created FileCreatedEvent
Handle File Modified FileModifiedEvent
Handle File Deleted FileDeletedEvent

Event Handler Examples

(* Handle new files *)
(Handle File Created: File Event Handler) {
    <Extract> the <path> from the <event: path>.
    <Log> the <file-created: message> for the <console>.
    <Return> an <OK: status> for the <event>.
}

(* Handle modified files *)
(Handle File Modified: File Event Handler) {
    <Extract> the <path> from the <event: path>.
    <Log> the <file-modified: message> for the <console>.
    <Return> an <OK: status> for the <event>.
}

(* Handle deleted files *)
(Handle File Deleted: File Event Handler) {
    <Extract> the <path> from the <event: path>.
    <Log> the <file-deleted: message> for the <console>.
    <Return> an <OK: status> for the <event>.
}

Common Patterns

Config Hot-Reload

(Application-Start: Hot Reload App) {
    (* Load initial config *)
    <Read> the <config: JSON> from the <file: "./config.json">.
    <Publish> as <app-config> <config>.

    (* Watch for config changes *)
    <Watch> the <file-monitor> for the <directory> with ".".

    <Start> the <http-server> on port <config: port>.
    <Wait> for <shutdown-signal>.
    <Return> an <OK: status> for the <startup>.
}

(Handle File Modified: File Event Handler) {
    <Extract> the <path> from the <event: path>.

    if <path> is "./config.json" then {
        <Log> the <message> for the <console> with "Reloading configuration...".
        <Read> the <new-config: JSON> from the <file: "./config.json">.
        <Publish> as <app-config> <new-config>.
        <Log> the <message> for the <console> with "Configuration reloaded".
    }

    <Return> an <OK: status> for the <reload>.
}

File Upload Processing

(Application-Start: Upload Processor) {
    <Watch> the <file-monitor> for the <directory> with "./uploads".
    <Start> the <http-server> on port 8080.
    <Wait> for <shutdown-signal>.
    <Return> an <OK: status> for the <startup>.
}

(POST /upload: Upload API) {
    <Extract> the <file-data> from the <request: body>.
    <Extract> the <filename> from the <request: headers filename>.

    <Write> the <file-data> to the <file: "./uploads/${filename}">.

    <Return> a <Created: status> with { filename: <filename> }.
}

(Handle File Created: File Event Handler) {
    <Extract> the <path> from the <event: path>.

    (* Only process files in uploads directory *)
    if <path> starts with "./uploads/" then {
        <Read> the <content> from the <file: path>.
        <Transform> the <processed> from the <content>.
        <Write> the <processed> to the <file: "./processed/${filename}">.
        <Delete> the <file: path>.
        <Log> the <message> for the <console> with "Processed: ${path}".
    }

    <Return> an <OK: status> for the <processing>.
}

Log File Management

(Application-Start: Logging App) {
    (* Create log directory if needed *)
    <Write> the <header> to the <file: "./logs/app.log">.
    <Return> an <OK: status> for the <startup>.
}

(Log Event: ApplicationEvent Handler) {
    <Extract> the <event-type> from the <event: type>.
    <Extract> the <event-data> from the <event: data>.

    <Create> the <log-entry> with {
        timestamp: <current-time>,
        type: <event-type>,
        data: <event-data>
    }.

    <Store> the <log-entry: JSON> into the <file: "./logs/app.log">.
    <Return> an <OK: status> for the <logging>.
}

Batch File Processing

(Process Batch: Scheduled Task) {
    <List> the <files> from the <directory: "./inbox">.

    for each <file> in <files> {
        <Read> the <content> from the <file: file>.
        <Process> the <result> from the <content>.
        <Write> the <result> to the <file: "./outbox/${file.name}">.
        <Delete> the <file: file>.
    }

    <Return> an <OK: status> for the <batch>.
}

File Paths

Relative Paths

<Read> the <content> from the <file: "./config.json">.       (* Relative to app *)
<Read> the <content> from the <file: "../shared/data.json">. (* Parent directory *)

Absolute Paths

<Read> the <content> from the <file: "/etc/myapp/config.json">.

Path Construction

<Create> the <path> with "./uploads/${user-id}/${filename}".
<Write> the <data> to the <file: path>.

Best Practices

Always Handle Missing Files

(Load Data: Initialization) {
    <Read> the <data: JSON> from the <file: "./data.json">.

    if <data> is empty then {
        (* Handle missing file *)
        <Create> the <data> with { items: [] }.
        <Write> the <data: JSON> to the <file: "./data.json">.
    }

    <Publish> as <app-data> <data>.
    <Return> an <OK: status> for the <loading>.
}

Validate File Types

(POST /upload: Upload API) {
    <Extract> the <filename> from the <request: headers filename>.
    <Extract> the <content-type> from the <request: headers Content-Type>.

    (* Validate file type *)
    when <content-type> is not "image/png" and <content-type> is not "image/jpeg" {
        <Return> a <BadRequest: status> for the <invalid: file-type>.
    }

    <Write> the <data> to the <file: "./uploads/${filename}">.
    <Return> a <Created: status> with { filename: <filename> }.
}

Use Appropriate Encodings

(* Text files *)
<Read> the <text> from the <file: "./data.txt">.

(* Binary files *)
<Read> the <binary: bytes> from the <file: "./image.png">.

(* JSON files *)
<Read> the <json: JSON> from the <file: "./config.json">.

Clean Up Temporary Files

(Process File: Temporary Processing) {
    <Read> the <input> from the <file: "./input.txt">.
    <Write> the <temp> to the <file: "./temp/processing.tmp">.

    <Process> the <result> from the <temp>.

    <Write> the <result> to the <file: "./output.txt">.
    <Delete> the <file: "./temp/processing.tmp">.

    <Return> an <OK: status> for the <processing>.
}

Next Steps