reckfellENGINE

Reading files and external assets

Checked UTF-8 reads, write failures and PNG loading without editor import.

On this page

Text: a complete example

Attach FileDemo.cs to an ordinary Entity, build and run the level. It creates user://io-demo/message.txt, writes two UTF-8 lines, reads them and prints the text followed by File demo: Ok. Another run overwrites this teaching file.

WriteText() accepts a path defined by your code. ReadText() returns an empty string on failure and limits input to 1 MiB. Here OutOfMemory means the example's size limit was exceeded. using closes the file even on an early return.

FileDemo.cs
C#
using System.Text;
using Reckfell;

public partial class FileDemo : Entity
{
    public const string Folder = "user://io-demo";
    public const string Note = Folder + "/message.txt";
    public const int MaxBytes = 1024 * 1024;
    private static readonly UTF8Encoding Utf8 = new(false, true);

    public static Error WriteNote(string text) => WriteText(Note, text);

    public static Error WriteText(string path, string text)
    {
        try
        {
            if (Utf8.GetByteCount(text) > MaxBytes)
                return Error.OutOfMemory;
        }
        catch (EncoderFallbackException)
        {
            return Error.InvalidData;
        }
        Error error = DirAccess.MakeDirRecursiveAbsolute(path.GetBaseDir());
        if (error != Error.Ok)
            return error;
        using var file = FileAccess.Open(path, FileAccess.ModeFlags.Write);
        if (file is null)
            return FileAccess.GetOpenError();
        return file.StoreString(text) ? file.GetError() : Error.FileCantWrite;
    }

    public static Error ReadText(string path, out string text)
    {
        text = "";
        using var file = FileAccess.Open(path, FileAccess.ModeFlags.Read);
        if (file is null)
            return FileAccess.GetOpenError();
        ulong length = file.GetLength();
        if (length > MaxBytes)
            return Error.OutOfMemory;
        byte[] bytes = file.GetBuffer((long)length);
        if ((ulong)bytes.Length != length)
            return Error.FileCorrupt;
        try
        {
            text = Utf8.GetString(bytes);
            return Error.Ok;
        }
        catch (DecoderFallbackException)
        {
            return Error.InvalidData;
        }
    }

    public override void _Ready()
    {
        Error error = WriteNote("Reckfell: привет\nSecond line");
        if (error == Error.Ok)
        {
            error = ReadText(Note, out string text);
            if (error == Error.Ok)
                ReckfellApi.Print(text);
        }
        ReckfellApi.Print($"File demo: {error}");
    }
}

Open() returns null on failure. Obtain GetOpenError() immediately, before another file open in the same thread. Check both opening and writing. Reading distinguishes an empty file from failure and rejects malformed UTF-8.

This is a direct synchronous overwrite, without backup or power-loss recovery guarantees. Use the replacement and backup slot for progress. Do not write the same slot from several tasks concurrently.

Open modes

ModeBehavior
ReadReads an existing file
WriteCreates a file or truncates an existing one
ReadWriteReads and writes an existing file without initial truncation
WriteReadCreates or truncates, then permits writing and reading

To append, open an existing file with ReadWrite and call SeekEnd(). Use Write if it does not exist yet. Writing from the beginning without truncating can leave an old suffix.

External image

Copy a PNG to user://io-demo/preview.png. Create a TextureRect and an ordinary Entity with ExternalPreview.cs; assign its Target. The first load runs in _Ready(). Call Reload() from your button handler for another load. Error.Ok means the new texture was assigned; failure retains the old one. Give TextureRect a nonzero size to make it visible. Enable WithMipmaps for downsampling with a suitable filter or for 3D use.

ExternalPreview.cs
C#
using Reckfell;

public partial class ExternalPreview : Entity
{
    [Export] public string ImagePath { get; set; } = "user://io-demo/preview.png";
    [Export] public TextureRect Target { get; set; } = null!;
    [Export] public bool WithMipmaps { get; set; }

    public override void _Ready() => ReckfellApi.Print(Reload());

    public Error Reload()
    {
        if (!ReckfellObject.IsInstanceValid(Target))
            return Error.Unconfigured;
        if (!FileAccess.FileExists(ImagePath))
            return Error.FileNotFound;
        using var image = new Image();
        Error error = image.Load(ImagePath);
        if (error != Error.Ok)
            return error;
        if (WithMipmaps)
        {
            error = image.GenerateMipmaps();
            if (error != Error.Ok)
                return error;
        }
        ImageTexture texture = ImageTexture.CreateFromImage(image);
        Target.Texture = texture;
        return Error.Ok;
    }
}

Load project images with ResourceLoader.Load<Texture2D>(); the export may contain an imported resource rather than the source PNG.

Other external formats

DataAPI and next step
WAV, Ogg Vorbis, MP3AudioStreamWav.LoadFromFile(), AudioStreamOggVorbis.LoadFromFile(), AudioStreamMP3.LoadFromFile(); check the result, assign AudioStreamPlayer.Stream, then Play()
TTF / OTFCreate a new FontFile, call LoadDynamicFont(path) and check the file/data; Error.Ok alone is insufficient. Assign through a theme or AddThemeFontOverride() after checking
glTF / GLBGltfDocument.AppendFromFile(path, state) → check Error.Ok → GenerateScene(state) → AddChild() on the main thread
ZIPZipReader.Open() → GetFiles() / FileExists() → ReadFile() → Close(); reading an entry does not extract it to disk
Write ZIPZipPacker.Open() → StartFile() → WriteFile() → CloseFile() → Close(); check each Error
Custom C# binary formatbyte[], System.Buffers.Binary.BinaryPrimitives and an explicit byte-order convention; byte[] has no Variant-array decode_* methods

For fonts, first check file existence, nonempty size and an acceptable read limit. This implementation resets state, reads bytes, assigns them and returns Ok without checking decoding success. Nonempty FontFile.Data establishes only that data exist: also check required characters and display. Reload into a new resource so the currently used font is not reset before validation.

An external model does not pass through the full editor import pipeline; your code must configure behavior, collisions and allowed dependencies. Define file-size limits and accepted formats for your application. Reading ZIP entries into memory does not itself bound the decompressed size.

Diagnostics

FailureCheck
FileNotFoundActual path, case and file existence
CantCreate, FileNoPermissionParent directory, permissions, space and file access
FileCorruptThe number of read bytes differed from the file length
InvalidData in the text exampleThe file is not valid UTF-8
Font returns Ok but text is absentFile, size limit, FontFile.Data, supported format and required characters; Ok does not establish decoding success
Asset works in the editor but is missing after exportUse the imported-resource loader or explicitly ship the external source file
Texture loads but remains invisibleTarget, TextureRect size and visibility; for 3D, material and surface
Reckfell Engine documentationBack to top ↑
QUICK LINKSGetting startedEntity hierarchyC# & .NET 10Scenes and prefabs
Reckfell guides and full API K
reckfellENGINE
RECKFELL ACCOUNT

Sign in

Sign in to your Reckfell account.

One account for the entire Reckfell platform.