1

I have DataWriter that has file storage stream already attached. how ever in particular case I want to first write data in memory so I can know size of bytes, and store size with data in writer.

How can I do that without creating two in memory buffers?

DataWriter writer; // writer is parameter passed from somewhere else.

using (var inMemory = new InMemoryRandomAccessStream())
{
    // fill inMemory with data.

    // ***Here*** How can I avoid this?
    var buffer = new byte[checked((int)inMemory.Position)].AsBuffer();

    inMemory.Seek(0);
    await inMemory.ReadAsync(buffer, buffer.Length, InputStreamOptions.ReadAhead);

    writer.WriteUInt32(buffer.Length); // write size
    writer.WriteBuffer(buffer); // write data
}

As you can see I'm using two buffers, one is for memory stream, the other is ibuffer.

I don't know how to directly write inMemory contents into DataWriter which has filestorage stream already attached.

M.kazem Akhgary
  • 18,645
  • 8
  • 57
  • 118
  • 2
    If you have a random access (seekable) stream, mark the position, write a length of 0, write the bytes directly to the stream, then overwrite the length with the correct value once you know how many bytes were written. Note: I know absolutely nothing about UWP and `DataWriter`, this is just how you do that in general. – Jeroen Mostert Sep 27 '17 at 09:35
  • @JeroenMostert DataWriter doesn't have seek method. the underlying stream supports random access and seek. but datawriter is wrapper around that, so I don't have direct access to underlying stream. DataWriter is sequential writer, it provides easy to use methods to write data into stream, (like BinaryWriter). It has its own buffer and may or may not commit buffer into underlying stream, so I guess that's why seeking is not supported. – M.kazem Akhgary Sep 27 '17 at 09:50

1 Answers1

0

I had to write my own buffer stream in order to prevent duplicate buffer creation. though stream buffer internally works like list but it has benefits when list grows large.

internal sealed class BufferStream : IDisposable
{
    private byte[] _array = Array.Empty<byte>();
    private int _index = -1;
    private const int MaxArrayLength = 0X7FEFFFFF;

    public int Capacity => _array.Length;
    public int Length => _index + 1;

    public void WriteIntoDataWriterStreamAsync(IDataWriter writer)
    {
        // AsBuffer wont cause copy, its just wrapper around array.
        if(_index >= 0) writer.WriteBuffer(_array.AsBuffer(0, _index)); 
    }

    public void WriteBuffer(IBuffer buffer)
    {
        EnsureSize(checked((int) buffer.Length));

        for (uint i = 0; i < buffer.Length; i++)
        {
            _array[++_index] = buffer.GetByte(i);
        }
    }

    public void Flush()
    {
        Array.Clear(_array, 0, _index);
        _index = -1;
    }

    // list like resizing.
    private void EnsureSize(int additionSize)
    {
        var min = additionSize + _index;
        if (_array.Length <= min)
        {
            var newsize = (int) Math.Min((uint) _array.Length * 2, MaxArrayLength);
            if (newsize <= min) newsize = min + 1;
            Array.Resize(ref _array, newsize);
        }
    }

    public void Dispose()
    {
        _array = null;
    }
}

Then I can easily do this.

using (var buffer = new BufferStream())
{
    // fill buffer

    writer.WriteInt32(buffer.Length); // write size
    buffer.WriteIntoDataWriterStream(writer); // write data
}
M.kazem Akhgary
  • 18,645
  • 8
  • 57
  • 118