Monthly Archives: July 2010

Measure Amount of Data to Serialize with a Null Stream

If you’ve got to serialize some data, especially in a binary format, it’s common to output the length of the data. This is useful for versioning, random access, knowing when you’re done reading the records, among other reasons.

Therefore, you need to know the size of the data you’re going to serialize. There are a few ways to do this:

  1. Measure the position you’re at, write the data, measure the new position, subtract, and that’s your length.
  2. If you want to write the length first (which is usually better), you can write a dummy value, such as 0, then writing the data, then backing up in the stream, and writing the real value.
  3. If you can’t back up the stream (very possible in some situations, or undesirable in others), you can measure the amount of data before you write. However, now you have to maintain that code in addition to the actual serialization.
  4. My solution presented here, avoids having to maintain separate code by writing the data to a null stream which does not write any data, but keeps track of how much data was “written.”
class NullStream : System.IO.Stream
{
    public override bool CanRead { get { return false; } }
 
    public override bool CanSeek { get { return false; } }
 
    public override bool CanWrite {get { return true; } }
 
    public override void Flush() { /*do nothing*/ }
 
    public override long Length { get { return Position; } }
 
    private long _position = 0;
    public override long Position 
    { 
        get 
        {
            return _position;
        }
        set
        {
            _position = value;
        }
    }
 
    public override int Read(byte[] buffer, int offset, int count)
    {
        throw new InvalidOperationException();
    }
 
    public override void Write(byte[] buffer, int offset, int count)
    {
        Position += count;
    }
 
    public override long Seek(long offset, System.IO.SeekOrigin origin)
    {
        throw new InvalidOperationException();
    }
 
    public override void SetLength(long value)
    {
        throw new InvalidOperationException();
    }
}

You can use it like this:

long GetDataSize()
{
    using (NullStream stream = new NullStream())
    {
        if (SaveData(stream))
        {
            return stream.Position;
        }
    }
    return 0;
}

There is a downside to something like this: you’re still essentially doing a lot of the work of serialization. Sure, you’re not writing out the bytes anywhere, but if, say, you need to encode a string as bytes before writing to the stream, that’s still going to happen.

Still, this technique made sense in my case, maybe it will work for you.