【问题标题】:MemoryStream troubles内存流问题
【发布时间】:2012-07-20 03:59:06
【问题描述】:

我在使用 MemoryStream 时遇到了一些问题

我们正在使用第 3 方电子表格组件(类似于 excel),我正在尝试通过下面的 SaveHtml 方法将数据保存为它们支持的 html。根据他们的文档,看起来非常简单。这是我的代码:

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

   memoryStream.Position = 0;

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

设置memoryStream.Position = 0时出现异常:

System.ObjectDisposedException: Cannot access a closed Stream.

快速浏览一下他们在 Reflector 中的 SaveHtml 方法会发现以下相关行:

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

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

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

我猜是因为 streamWriter 被他们的代码关闭了,我们不走运。关闭streamWriter,也就关闭了底层Stream吧?

有什么办法可以解决这个问题?

谢谢。

【问题讨论】:

  • memoryStream.GetBuffer() 应该仍然可以工作,恕我直言
  • @user1096188:根据消息来源,应该!发布为答案。好东西要记住,谢谢;)

标签: c# .net stream memorystream


【解决方案1】:

它似乎有效,因此您可以创建另一个内存流。提取缓冲区时不复制任何字节。

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();
    }
}

或者您可以推出自己的不可关闭的 MemoryStream 并将其提供给 SaveHtml。这也将阻止处理它,因为 Dispose 只是调用 Close。再次,恕我直言:

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

【讨论】:

  • .GetBuffer() 最后可能会返回垃圾字节。请改用.ToArray()(在流关闭时也可以使用)。您可以简单地调用Encoding.UTF8.GetString(memoryStream.ToArray()),而不是创建另一个内存流。
  • @user1096188:最好覆盖Dispose。关于覆盖的好主意永远不会少:) +1
  • @Allon 你确定会有垃圾吗?我尝试运行Console.WriteLine(new MemoryStream(1024 * 1024 * 1024).GetBuffer().Any(b => b != 0)); 几次,它总是打印false...
  • @user1096188 保证缓冲区是零初始化的。我认为 Allon 的观点是缓冲区可能大于流的内容。如果流在某个点被缩短,“额外”字节可能不为零。在这种情况下,我怀疑这是一种风险。另外,虽然我不确定 StreamReader 最后会如何处理额外的零字节,但我怀疑处理它们就好了。
【解决方案2】:

在这种情况下可以使用替代的memory stream 实现:

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);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-10-14
    • 2011-08-03
    • 2016-06-17
    • 1970-01-01
    • 2018-08-19
    • 2020-12-10
    • 2015-05-27
    • 1970-01-01
    相关资源
    最近更新 更多