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,LengthandCreateInStreamon the same variable right away,
before Modify. Reloading the variable (Get, Find*, Next, Init, Clear) discards an unsaved write, as in standard AL.
- A
CreateOutStreamon 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.CodeBloberrors) 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;