Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
The AL language in Business Central supports streaming data. This article introduces streams and explains how to use them in your app.
What is a stream?
A stream is an abstraction of a sequence of bytes, such as a file, an input/output device, an inter-process communication pipe, or a TCP/IP socket. The stream data types in AL provide a generic view of these different types of input and output. They isolate the developer from the specific details of the operating system and the underlying devices.
Streams involve three fundamental operations:
- You can read from streams
Reading is the transfer of data from a stream into a data structure, such as a Text or Blob. - You can write to streams
Writing is the transfer of data from a data structure such as Text or Blob into a stream. - Streams can support seeking
Seeking refers to querying and modifying the current position within a stream. Seek capability depends on the kind of backing store a stream has. For example, network streams have no unified concept of a current position, and therefore typically don't support seeking.
A stream is an object used for transferring data, so the stream doesn't store any actual data. When you work with streams in AL, you need three things.
- A data source such as a file, a Blob, or an HTTP request
- A stream object connected to the data source. The stream has a direction of reading or writing data to or from the data source.
- An object in the AL runtime acting as the consumer or the emitter of the data.
How are streams implemented in AL?
The AL stream object and methods wrap corresponding .NET stream concepts. In C#, you use a single object called Stream. The direction (read or write) is clear when you use the Read and Write methods, as shown in this C# example:
// how to write the content of one stream into another stream in C#
static void CopyStream(Stream input, Stream output){
byte[] buffer = new byte[0x1000];
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
output.Write(buffer, 0, read);
}
In AL, the direction of the data flow is clear in the two data types InStream and OutStream. Use an AL object to either consume (read) data from a data source through a stream or emit (write) data to a data source through a stream.
The AL runtime includes a method for copying a stream. Learn more in System.CopyStream(OutStream: OutStream, InStream: InStream [, BytesToRead: Integer]).
Note
The CopyStream method comes from the time of the C/AL programming language, which was inspired by the Pascal programming language. In Pascal, procedures typically follow the direction of assignments. For example, variable := value (like dest := source). This behavior explains the order of parameters in CopyStream.
Reading data with the InStream data type
The InStream data type provides a generic stream object with methods that you can use to read from streams. The data type also provides methods to change the position in the stream and a way to get the size of the data source object without reading all of the data.
An instance of the InStream data type must be attached to a data source to work. Otherwise, you get a runtime error stating that InStream variable not initialized..
trigger OnAction()
var
vInStr: InStream;
begin
// this will trigger a runtime error
Message(Format(vInStr.Length()));
end;
The following example shows how to read the content from a media field in the database by using an InStream object.
procedure ReadTextFromMediaResource(MediaResourcesCode: Code[50]) MediaText: Text
var
MediaResources: Record "Media Resources";
TextInStream: InStream;
begin
if not MediaResources.Get(MediaResourcesCode) then
exit;
MediaResources.CalcFields(Blob);
// After this call, the TextInStream is ready to stream data from the blob field
MediaResources.Blob.CreateInStream(TextInStream, TextEncoding::UTF8);
TextInStream.Read(MediaText);
end;
Learn more in InStream datatype (reference documentation).
Writing data with the OutStream datatype
The OutStream datatype provides a generic stream object with methods that you can use to write to resources using streams.
An instance of the OutStream datatype must be attached to a data source to work. Otherwise, you get a runtime error stating that InStream variable not initialized..
The following example illustrates how to read the content from an uploaded file by using an InStream object and then copy the stream content into a blob field by using an OutStream object.
procedure InsertBLOBFromFileUpload()
var
FromFilter: Text;
File: File;
FileInStream: InStream;
BLOBOutStream: OutStream;
MyTable : Record "Some table";
begin
FromFilter := 'All Files (*.*)|*.*';
UploadIntoStream(FromFilter, FileInStream);
MyTable.Init();
MyTable.Blob.CreateOutStream(BLOBOutStream);
CopyStream(BLOBOutStream, FileInStream);
MyTable.Insert(true);
end;
Learn more in OutStream datatype (reference documentation)
Why use streams?
- Memory efficiency: Streams allow you to work with large amounts of data without loading it all into memory at once. If you can stream data instead of storing it in a variable, the Business Central server handles fewer large objects when the operating system does garbage collection. This improvement enhances the general performance of the system.
- Performance efficiency: Streams allow you to work with data as it becomes available, rather than waiting for all of it to arrive.
- When working with Business Central online, you can't use the file system directly. Streams provide a way to work with data without having to store it in a file.
Examples of stream support
Many AL data types and objects can consume data from streams or emit data to streams. The following table provides some examples. The list isn't exhaustive.
| Data source | Consume data with InStream | Emit data with OutStream |
|---|---|---|
| Web service | Read data from stream: HttpContent.ReadAs Send data using stream: HttpContent.WriteFrom |
|
| Local file (only for on-premises) | File.CreateInStream | File.CreateOutStream |
| File upload/download | DownloadFromStream | UploadIntoStream |
| XML document | XmlDocument.ReadFrom | XmlDocument.WriteTo |
| JSON document | JsonObject.ReadFrom | JsonObject.WriteTo(OutStream) |
| Media/MediaSet | Media.ImportStream MediaSet.ImportStream |
Media.ExportStream |
| Excel (in-memory buffer) | OpenBookStream | SaveToStream |
| CSV (in-memory buffer) | LoadDataFromStream | |
| Blob field in the database | Temp Blob codeunit | Temp Blob codeunit |
Tip
When streaming binary data, you might need to do a Base64 encoding to make it available as a text stream. The System Application has a module for this. Learn more in Codeunit "Base64 Convert".
Streaming text data
When streaming text data, you need to be aware of encodings, which the TextEncoding Option Type typically controls. Learn more in Text encoding.
You might also want to learn more about the semantics of line endings and zero byte terminators. Learn more in Write, WriteText, Read, and ReadText method behavior for line endings and zero terminators.
Preview files in the Business Central client
In addition to reading and writing data, you can use streams to display files directly in the Business Central client.
Use the File.ViewFromStream method in Business Central online environments to open supported files in the built-in previewer. For on-premises environments, use the File.View method. These methods follow the same general pattern as File.DownloadFromStream and File.Download, but preview supported files in the client instead of downloading them first.
Unlike File.DownloadFromStream, which downloads content to the user's device, these methods display the file in the client. Users can preview supported PDF and image files and then download a copy from the previewer if they need one.
Supported image formats include JPEG, JPG, PNG, BMP, SVG, WEBP, ICO, GIF, and AVIF. GIF and AVIF formats include support for animated files. On Safari, TIFF and TIF images are also supported.
Example:
TempBlob.CreateInStream(InStream);
File.ViewFromStream(InStream, 'Sample.png', true);
Related information
InStream datatype (AL reference documentation)
OutStream datatype (AL reference documentation)
System.CopyStream method (AL reference documentation)
Codeunit "Base64 Convert" (System Application reference documentation)
TextEncoding Option Type
Text encoding
Write, WriteText, Read, and ReadText method behavior for line Endings and Zero Terminators