John Russell
John Russell

Reputation: 2247

MemoryStream troubles

I'm having some trouble using a MemoryStream

We're using a 3rd party spreadsheet component (similar to excel), and I'm trying to save the data as html which they support through the SaveHtml method below. Seems very simple based on their documentation. Here is my code:

using (var memoryStream = new MemoryStream())
{
   this.ActiveSheet.SaveHtml(memoryStream);

   memoryStream.Position = 0;

   using (var streamReader = new StreamReader(memoryStream))
   {
       var htmlData = streamReader.ReadToEnd();
   }
}

I get an exception when I set the memoryStream.Position = 0:

System.ObjectDisposedException: Cannot access a closed Stream.

A quick look at their SaveHtml method in Reflector shows the following relevant lines:

public void SaveHtml(Stream stream)
{
    StreamWriter writer = null;

    try
    {
        writer = new StreamWriter(stream) { AutoFlush = true };

        writer.Write(str);
    }   
    finally
    {
        if (writer != null)
        {
            writer.Close();
        }
    }
}

I'm guessing because the streamWriter is closed by their code, we're out of luck. Closing the streamWriter, closes the underlying Stream, right?

Any way to get around this?

Thanks.

Upvotes: 5

Views: 5392

Answers (2)

ryanovic
ryanovic

Reputation: 134

Alternative memory stream implementation can be used in such context:

var stream = new ChunkedStream(pool, asOutputStreamOnDispose: true);

using (var writer = new StreamWriter(stream))
{
    writer.Write("hello world");
}

Assert.AreEqual(0, stream.Position);
Assert.AreEqual(ChunkedStreamState.ReadForward, stream.State);
Assert.AreEqual(3, pool.TotalAllocated);

using (var reader = new StreamReader(stream))
{
    Assert.AreEqual("hello world", reader.ReadToEnd());
    Assert.AreEqual(0, pool.TotalAllocated);
}

Assert.AreEqual(ChunkedStreamState.Closed, stream.State);

Upvotes: 0

user1096188
user1096188

Reputation: 1839

It seems it works, so you can create another memory stream. No bytes are copied when extracting the buffer.

using (var memoryStream = new MemoryStream()) {
    this.ActiveSheet.SaveHtml(memoryStream);
    var buffer = memoryStream.GetBuffer();
    using (var memoryStream2 = new MemoryStream(buffer))
    using (var streamReader = new StreamReader(memoryStream2)) {
        var htmlData = streamReader.ReadToEnd();
    }
}

Or you can roll out your own uncloseable MemoryStream and feed it to SaveHtml. This will also prevent disposing it, since Dispose just calls Close. Again, imho:

class MemoryStream2 : MemoryStream {
    public override void Close() { }
}

Upvotes: 6

Related Questions