This class provides serialization of binary data in a platform-independent way. It will work with any IODevice. To serialize some data to a File, for example, write code like this:
int someInt;
wchar[] someWString;
// ...
try
{
auto File file = new File("data.bin");
file.open(IODevice.WriteOnly | IODevice.Truncate);
DataStream stream = new DataStream(file);
stream << cast(uint) 0x3579; // "Magic number".
stream << someInt;
stream << someWString;
}
catch (Exception e)
{
printf("Serialization failed.\n");
e.print();
}
This example already includes full error handling. DataStream provides the shifting operators for all basic D types and dynamic arrays of them. Reading back the data is roughly the same (error handling stripped):
file.open(IODevice.ReadOnly);
// ...
uint magic;
stream >> magic;
if (magic != 0x3579)
throw new DataStreamException("Unrecognized file format.");
stream >> someInt;
stream >> someWString;
If DataStream cannot read what you requested because the stream signals EOF, it will throw a DataStreamException. Note that it cannot recover from uncomplete reading operations, thus you always have to provide enough data (this is particularly important when reading from “slow” devices like sockets).
As you can see in the above examples, it is very important to write only fixed-size types, or “fix” their size with a cast before writing. Do not send types or expressions of unknown size (like size_t, someArray.length, 2983922) into the stream. Luckily, the D basic types all have a fixed size ─ except real, which consequently DataStream has no shifting operators for.
There are also two functions to deal with raw binary data: writeRawData() and readRawData(). You can control the stream’s behaviour with device and byteOrder. Note that the default ByteOrder is LittleEndian, in contrast to Qt’s QDataStream where it is BigEndian. You have to switch it if you try to read files from Qt.
If you want to make your own types serializable with DataStream, give them these two member functions:
void readFrom(DataStream st);
void writeTo(DataStream st);
Containers like Vector will automatically provide these functions if your types do as well. Note that this will not work for classes, as they need to be allocated at first. You have two options to make them serializable:
- Provide a default constructor this(). The container will create a new object with this constructor, and then call readFrom() on it.
- Provide a static function createFrom() which returns a new object created from the stream. With this approach it is even possible to serialize objects created from derived classes, and save them into a container that manages references to their base class.
static MyClass createFrom(DataStream st);
The second method is the one preferred by the Indigo containers.
Summary
| |
| This enum specifies the byte order used for serializing data. |
| |
| Creates a new, unconnected DataStream. |
| Creates a new DataStream that is connected to the IODevice dev. |
| Returns the device that is currently connected to the stream. |
| |
| Writes the contents of data directly to the stream. |
| Reads the contents of data directly from the stream. |
| |
| Writes a single byte to the stream. |
| Writes an array of bytes to the stream. |
| Reads a single byte from the stream. |
| Reads an array of bytes from the stream. |