Reading Files in Bnlang

Reading files is one of the most common things a program does. The built-in io module gives you three flavors, from simplest to most powerful:

  • io.read_file(path) — synchronous; returns the whole file as a string.
  • io.read_file_async(path, cb) — asynchronous; the callback receives the data when ready.
  • io.open_read(path) — streaming; pull the file in chunks for memory-friendly processing.

Synchronous Read

The simplest form. Blocks the event loop until the whole file is in memory. Use this in scripts and for small files.

import "io" as io;

var text = io.read_file("notes.txt");
print(text);

Asynchronous Read

Returns immediately. The callback is invoked once the read completes — first argument is the error (or null), second is the file contents.

import "io" as io;

io.read_file_async("notes.txt", function (err, data) {
    if (err != null) {
        print("read failed:", err);
        return;
    }
    print("got", data.byte_length, "bytes");
});
print("scheduled — keep doing other work");

Streaming Large Files

For files that don't fit comfortably in memory, open a read stream and pull chunks. The callback receives chunk = null to signal EOF.

import "io" as io;

var src   = io.open_read("big.log");
var total = 0;

function on_chunk(err, chunk) {
    if (err != null) { print("read err:", err); src.close(); return; }
    if (chunk == null) {
        print("done. total:", total, "bytes");
        src.close();
        return;
    }
    total = total + chunk.byte_length;
    src.read(64 * 1024, on_chunk);
}

src.read(64 * 1024, on_chunk);

Best Practices

  • Reach for io.read_file_async by default in long-running programs (servers, daemons).
  • Use the sync variant for one-shot scripts where simplicity wins.
  • For files larger than, say, a few megabytes, prefer io.open_read so you don't allocate a huge string.
  • Always call src.close() when you're done with a stream — otherwise the OS file handle stays open.