Erik's ToolBox Documentation
Index

Streams (InStream and OutStream)

Streams let scripts read and write binary or text data sequentially. An OutStream writes data into a backing store; an InStream reads it back. Streams are the bridge between JSON, files, blobs, compression, and REST payloads.

Getting a Stream

Streams are not created on their own — you obtain them from a backing object: a Blob field on a record (see below) or, most commonly, the Temp Blob codeunit, which provides an in-memory blob you can write to and then read from:

var
    Blob: Codeunit "Temp Blob";
    Out: OutStream;
    In: InStream;
    Line: Text;
begin
    Blob.CreateOutStream(Out);       // optional 2nd arg: encoding (utf8 default)
    Out.WriteText('First line');
    Out.WriteText();                 // write a line terminator
    Out.WriteText('Second line');

    Blob.CreateInStream(In);
    while not In.Eos() do begin
        Line := In.ReadText();
        Message('Read: %1', Line);
    end;
end;

Other stream sources include uploadintostream (a client file), the Data Compression codeunit, and JSON WriteTo/ReadFrom.

Blob Fields on Records

A Blob field on a record opens streams directly, the way it does in standard AL. Write through an OutStream, then Insert or Modify to persist the content; after loading a record from the database, CalcFields the Blob before reading it:

var
    Prog: Record "Program Hgd";
    Out: OutStream;
    In: InStream;
    Line: Text;
begin
    Prog.Get('DEMO');
    Prog.CodeBlob.CreateOutStream(Out, TextEncoding::UTF8);
    Out.WriteText('stored in the field');
    Prog.Modify();

    Prog.Get('DEMO');
    Prog.CalcFields(CodeBlob);
    if Prog.CodeBlob.HasValue then begin
        Prog.CodeBlob.CreateInStream(In, 'utf8');
        In.ReadText(Line);
        Message('%1 (%2 bytes)', Line, Prog.CodeBlob.Length);
    end;
end;
Member Returns Notes
CreateOutStream(var OutStream) Writes land in the record; Insert/Modify persist them
CreateOutStream(var OutStream, Encoding) Encoding: 'utf8' (default) / 'utf16' / 'msdos' / 'windows', or TextEncoding::UTF8 etc.
CreateInStream(var InStream) Every call starts at the beginning
CreateInStream(var InStream, Encoding) Same encoding options
HasValue Boolean Parentheses optional
Length Integer Size in bytes

Notes:

  • A write is visible to HasValue, Length and CreateInStream on the same variable right away,

before Modify. Reloading the variable (Get, Find*, Next, Init, Clear) discards an unsaved write, as in standard AL.

  • A CreateOutStream on a field that already holds data writes over the existing bytes from the

start without truncating them (standard AL behaviour): writing modified over hello blob leaves modifiedob. To replace content, Clear(Rec.BlobField) first, then open a new OutStream.

  • The Blob field cannot be read or assigned as a value (Txt := Rec.CodeBlob errors) and

Import/Export (file dialogs) are not available; use UploadIntoStream/DownloadFromStream.

  • Persist through the same record variable that opened the stream. A Temp Blob

ToRecordRef on the same field while a stream is open is overwritten by the open stream at the next Insert/Modify.

InStream Members

Member Returns Description
readtext() Text Read and return the next line
readtext(var Text) Text Fill the variable; returns the number of characters read
eos() Boolean End of stream
length() Integer Size in bytes
position() Integer Current read position
resetposition() Move back to the start of the stream
var
    Blob: Codeunit "Temp Blob";
    Out: OutStream;
    In: InStream;
    Content: Text;
begin
    Blob.CreateOutStream(Out);
    Out.WriteText('Hello');
    Blob.CreateInStream(In);

    Message('Stream length: %1 bytes', In.Length());
    In.ReadText(Content);
    Message('Content: %1', Content);

    In.ResetPosition();              // read again from the beginning
end;

OutStream Members

Member Returns Description
writetext(Text) Integer Write text; returns the number of characters
writetext() Integer Write a line terminator only

Call WriteText('...') followed by a bare WriteText() to produce line-delimited output that InStream.ReadText() can read back one line at a time.

Only the text members listed above are available. The binary Read/Write overloads of standard AL streams are not supported; move binary content with CopyStream, Base64 Convert, or Data Compression. Streams are reference types: a stream passed to a procedure is the same stream, and reading through it advances the position for every alias.

Global Stream Helpers

Three global functions move data between streams and the client, independent of any codeunit.

copystream

copystream(toOutStream: OutStream, fromInStream: InStream)

Copies all remaining data from an InStream into an OutStream.

downloadfromstream

downloadfromstream(inStream: InStream, dialogTitle: Text, toFolder: Text, toFilter: Text, var toFile: Text): Boolean

Sends the contents of an InStream to the user as a file download. Returns false if the user cancels.

uploadintostream

uploadintostream(dialogTitle: Text, fromFolder: Text, fromFilter: Text, var fromFile: Text, var inStream: InStream): Boolean

Prompts the user to upload a file and exposes it as an InStream. Returns false if the user cancels.

var
    In: InStream;
    FileName: Text;
    Json: JsonObject;
begin
    if UploadIntoStream('Select a JSON file', '', 'JSON Files (*.json)|*.json', FileName, In) then
        if Json.ReadFrom(In) then
            Message('Loaded %1', FileName)
        else
            Message('%1 is not valid JSON', FileName);
end;

Example: Zip a Text File and Download It

Streams tie the feature set together — here text goes into a blob, the blob is added to a zip archive, and the archive is downloaded to the client.

var
    TextBlob: Codeunit "Temp Blob";
    ZipBlob: Codeunit "Temp Blob";
    Zip: Codeunit "Data Compression";
    TextOut: OutStream;
    TextIn: InStream;
    ZipOut: OutStream;
    ZipIn: InStream;
    FileName: Text;
begin
    // 1. Write some text into a blob
    TextBlob.CreateOutStream(TextOut);
    TextOut.WriteText('Report generated by ToolBox');

    // 2. Add it to a new zip archive
    TextBlob.CreateInStream(TextIn);
    Zip.CreateZipArchive();
    Zip.AddEntry(TextIn, 'report.txt');

    // 3. Save the archive to a stream and download it
    ZipBlob.CreateOutStream(ZipOut);
    Zip.SaveZipArchive(ZipOut);
    Zip.CloseZipArchive();

    ZipBlob.CreateInStream(ZipIn);
    FileName := 'report.zip';
    DownloadFromStream(ZipIn, 'Save archive', '', '', FileName);
end;