Input and Output Streams

4 min read

3 min read

3 min read

3 min read

3 min read

4 min read

An OutputStreamOutputStreamOutputStreamOutputStreamOutputStreamOutputStream encodes Slice values into bytes with the Ice encoding, and an InputStreamInputStreamInputStreamInputStreamInputStreamInputStream decodes them. The code generated by the Slice compilers uses these streams to encode and decode the parameters of operations.

Your application uses these streams directly to:

  • write the in-parameters of a dynamic invocation (ice_invoke) and read its results;
  • read the parameters and write the results in a servant that dispatches requests without generated code;
  • store Slice values in a file or a database, or send them through a channel other than an Ice connection.

Your application uses these streams directly to:

  • read the parameters and write the results in a servant that dispatches requests without generated code;
  • store Slice values in a file or a database, or send them through a channel other than an Ice connection.

Your application uses these streams directly to store Slice values in a file or a database, or send them through a channel other than an Ice connection.

The examples on this page use the following Slice structure:

Slice
module Inventory
{
struct Item
{
string name;
int quantity;
}
}

To encode an Item, you create an OutputStream, start an encapsulation, write the value, end the encapsulation, and call finished to get the encoded bytes. To decode it, you create an InputStream over these bytes and read the encapsulation and the value in the same order.

C++
Inventory::Item item{"widget", 12};
Ice::OutputStream out{communicator};
out.startEncapsulation();
out.write(item);
out.endEncapsulation();
std::vector<std::byte> bytes;
out.finished(bytes);
Ice::InputStream in{communicator, bytes};
in.startEncapsulation();
Inventory::Item decoded;
in.read(decoded);
in.endEncapsulation();

finished(std::vector<std::byte>& bytes) copies the encoded bytes into bytes. The finished() overload without parameters returns a pair of pointers to the stream's own buffer instead; these pointers remain valid for the lifetime of the stream.

C#
var item = new Inventory.Item("widget", 12);
var outputStream = new Ice.OutputStream(communicator);
outputStream.startEncapsulation();
Inventory.Item.ice_write(outputStream, item);
outputStream.endEncapsulation();
byte[] bytes = outputStream.finished();
var inputStream = new Ice.InputStream(communicator, bytes);
inputStream.startEncapsulation();
Inventory.Item decoded = Inventory.Item.ice_read(inputStream);
inputStream.endEncapsulation();
Java
var item = new Item("widget", 12);
var outputStream = new com.zeroc.Ice.OutputStream(communicator);
outputStream.startEncapsulation();
Item.ice_write(outputStream, item);
outputStream.endEncapsulation();
byte[] bytes = outputStream.finished();
var inputStream = new com.zeroc.Ice.InputStream(communicator, bytes);
inputStream.startEncapsulation();
Item decoded = Item.ice_read(inputStream);
inputStream.endEncapsulation();
JavaScript
const item = new Inventory.Item("widget", 12);
const outputStream = new Ice.OutputStream(communicator);
outputStream.startEncapsulation();
Inventory.Item.write(outputStream, item);
outputStream.endEncapsulation();
const bytes = outputStream.finished();
const inputStream = new Ice.InputStream(communicator, bytes);
inputStream.startEncapsulation();
const decoded = Inventory.Item.read(inputStream);
inputStream.endEncapsulation();

finished returns a Uint8Array.

MATLAB
item = Inventory.Item('widget', 12);
outputStream = Ice.OutputStream();
outputStream.startEncapsulation(Ice.FormatType.CompactFormat);
Inventory.Item.ice_write(outputStream, item);
outputStream.endEncapsulation();
bytes = outputStream.finished();
inputStream = Ice.InputStream(communicator, communicator.getEncoding(), bytes);
inputStream.startEncapsulation();
decoded = Inventory.Item.ice_read(inputStream);
inputStream.endEncapsulation();

Ice.OutputStream takes an optional encoding version and class format, and Ice.InputStream takes the communicator, the encoding version and the bytes to decode. startEncapsulation on an OutputStream takes the class format of the encapsulation. finished returns a uint8 row vector.

Swift
let item = Item(name: "widget", quantity: 12)
let outputStream = Ice.OutputStream(communicator: communicator)
outputStream.startEncapsulation()
outputStream.write(item)
outputStream.endEncapsulation()
let bytes = outputStream.finished()
let inputStream = Ice.InputStream(communicator: communicator, bytes: bytes)
try inputStream.startEncapsulation()
let decoded: Item = try inputStream.read()
try inputStream.endEncapsulation()

Foundation also defines InputStream and OutputStream classes, so qualify the Ice stream classes with Ice.. finished returns Data.

An encapsulation holds encoded values preceded by their size and their encoding version, as described in Encoding for Encapsulations. The Ice protocol carries the parameters of a request and the results of a reply in encapsulations. The in-parameters you pass to ice_invoke and the results it returns are such encapsulations, which you encode and decode as in the example above. A servant that dispatches requests without generated code reads the parameters from the encapsulation at the start of the request's input stream, and creates its response with the dispatcher API, which puts the results it writes in an encapsulation.

See OutputStreamOutputStreamOutputStreamOutputStreamOutputStream and InputStreamInputStreamInputStreamInputStreamInputStream for the constructors, the methods for the built-in types, and the errors the streams report.

The following table shows how you write and read the types you define in Slice:

write and read are templates that accept any type the Slice compiler generates:

Slice typeWriteRead
Structure
out.write(item)
in.read(item)
Enumeration
out.write(color)
in.read(color)
Sequence or dictionary
out.write(items)
in.read(items)
Proxy (std::optional<P>)
out.write(proxy)
in.read(proxy)
Class (std::shared_ptr)
out.write(instance)
in.read(instance)
Exception
out.writeException(error)
in.throwException()

throwException reads an exception and throws it.

Slice typeWriteRead
Structure S
S.ice_write(outputStream, value)
S.ice_read(inputStream)
Enumeration E
EHelper.write(outputStream, value)
EHelper.read(inputStream)
Sequence or dictionary T
THelper.write(outputStream, value)
THelper.read(inputStream)
Interface I (proxy)
IPrxHelper.write(outputStream, proxy)
IPrxHelper.read(inputStream)
Class C
outputStream.writeValue(instance)
inputStream.readValue<C>(callback)
Exception
outputStream.writeException(error)
inputStream.throwException()

throwException reads an exception and throws it.

Slice typeWriteRead
Structure or enumeration T
T.ice_write(outputStream, value)
T.ice_read(inputStream)
Sequence or dictionary T
THelper.write(outputStream, value)
THelper.read(inputStream)
Interface I (proxy)
outputStream.writeProxy(proxy)
IPrx.uncheckedCast(inputStream.readProxy())
Class C
outputStream.writeValue(instance)
inputStream.readValue(callback, C.class)
Exception
outputStream.writeException(error)
inputStream.throwException()

throwException reads an exception and throws it.

Slice typeWriteRead
Structure S
S.write(outputStream, value)
S.read(inputStream)
Enumeration E
outputStream.writeEnum(value)
inputStream.readEnum(E)
Sequence or dictionary T
THelper.write(outputStream, value)
THelper.read(inputStream)
Interface I (proxy)
outputStream.writeProxy(proxy)
inputStream.readProxy(IPrx)
Class C
outputStream.writeValue(instance)
inputStream.readValue(callback, C)
Exception
outputStream.writeException(error)
inputStream.throwException()

throwException reads an exception and throws it.

Slice typeWriteRead
Structure or enumeration T
T.ice_write(outputStream, value)
T.ice_read(inputStream)
Sequence or dictionary T
T.write(outputStream, value)
T.read(inputStream)
Interface I (proxy)
outputStream.writeProxy(proxy)
IPrx.ice_read(inputStream)
Class C
outputStream.writeValue(instance)
inputStream.readValue(callback, 'C')
Exception
inputStream.throwException()

For a sequence of a built-in type such as int or string, use the stream's own methods, such as writeIntSeq and readIntSeq. readValue passes the instance to the callback, and takes the class name qualified with its package. throwException reads an exception and throws it.

Slice typeWriteRead
Structure or enumeration T
outputStream.write(value)
let value: T = try inputStream.read()
Sequence or dictionary T
THelper.write(to: outputStream, value: value)
try THelper.read(from: inputStream)
Interface I (proxy)
outputStream.write(proxy)
try inputStream.read(IPrx.self)
Class C
outputStream.write(instance)
try inputStream.read(C.self, cb: callback)
Exception
outputStream.write(error)
try inputStream.throwException()

For a sequence of a built-in type such as int or string, use the stream's own write and read methods. throwException reads an exception and throws it.