Skip to content
FutureBlitz

    Install

    Compile-time code, 4 of 4

    Embedding files

    Build files into the executable with Embed, EmbedText, and EmbedFolder, so a program ships as one file.

    What you’ll build

    A greeting program whose help text and greetings are files beside its code, built into the executable, so it needs nothing beside it when it runs. You’ll embed one file as text, one as bytes, and a whole folder.

    A file as text

    EmbedText(path) reads a file when the program is built and gives its text as a String known at compile time, which a Const can hold. The path is from the folder of the file the call is in.

    help.txt
    Usage: greet [name]
    Prints a greeting in each language it knows.
    main.fb
    Import std.core
    Import std.text
    
    Const HELP = EmbedText("help.txt")
    
    Print(HELP.TrimEnd())
    Output
    Usage: greet [name]
    Prints a greeting in each language it knows.

    The text is in the executable: move the program anywhere, delete help.txt, and it still prints it. Change help.txt, and the next build has the new text. The file must be UTF-8.

    A file as bytes

    Embed(path) gives a file’s bytes, exactly as they are, in a new UInt8[] each time it runs. It’s for files that aren’t text, like images or archives, or for text you’ll decode yourself.

    help.txt
    Usage: greet [name]
    Prints a greeting in each language it knows.
    main.fb
    Import std.core
    
    Local bytes = Embed("help.txt")
    Print("help.txt is {bytes.Count} bytes, starting with {bytes[0]}")
    Output
    help.txt is 65 bytes, starting with 85

    A whole folder

    EmbedFolder(path) gives a new Map<String, UInt8[]> of every file in a folder and its folders, by its path in the folder, like "formal/en.txt", in path order. Hidden files and folders, whose names start with ., are left out.

    greetings/en.txt
    Hello, {name}!
    greetings/es.txt
    Hola, {name}!
    greetings/formal/en.txt
    Good day, {name}.
    main.fb
    Import std.core
    Import std.collections
    Import std.text
    
    Local greetings = EmbedFolder("greetings")
    
    For path In greetings.Keys()
        Local greeting = String.FromUtf8(greetings[path]) ?? ""
        Print("{path}: {greeting.TrimEnd().Replace("{{name}}", "Ada")}")
    End For
    Output
    en.txt: Hello, Ada!
    es.txt: Hola, Ada!
    formal/en.txt: Good day, Ada.

    String.FromUtf8 gives Null for bytes that aren’t valid UTF-8, so the code gives "" then. In the string, {{ and }} stand for the braces themselves, since a lone { starts an interpolation.

    Mistakes found at build time

    A path that names nothing is an error where it’s written, so a missing file never reaches a running program:

    Import std.core
    
    Const HELP = EmbedText("nope.txt")
    Print(HELP)
    $ fb run main.fb
       Compiling main.fb
    main.fb:3:24: error: "nope.txt" isn't a file: there's nothing at nope.txt
      |
    3 | Const HELP = EmbedText("nope.txt")
      |                        ^^^^^^^^^^
    error: couldn't build main.fb because of 1 error

    A path also has to stay inside the package’s folder, or for a program without a project.toml, the main file’s folder:

    Import std.core
    
    Local notes = Embed("../notes.txt")
    Print(notes.Count)
    $ fb run main.fb
       Compiling main.fb
    main.fb:3:21: error: "../notes.txt" leaves the main file's folder, which a program's embedded files are in
      |
    3 | Local notes = Embed("../notes.txt")
      |                     ^^^^^^^^^^^^^^
    error: couldn't build main.fb because of 1 error

    One call can embed at most 64 MiB. A file bigger than that is better read when the program runs, with std.io.

    What you learned

    • EmbedText builds a UTF-8 file into the program as a String known at compile time.
    • Embed builds in a file’s bytes, and EmbedFolder a folder’s files, by their paths.
    • Paths are from the calling file’s folder, and stay inside the package.
    • A missing file is a build error, and each build reads the files again.

    Report an issue with this page or with FutureBlitz on GitHub.