【问题标题】:Cannot access a closed Stream of a memoryStream, how to reopen?无法访问已关闭的 memoryStream 流,如何重新打开?
【发布时间】:2012-03-19 12:21:31
【问题描述】:

我有一个 memoryStream 实例,它已关闭。

我已经试过了:

memoryStream.Flush();
memoryStream.Position=0;

重新打开内存流但它不起作用。如何重新打开已关闭的内存流?

【问题讨论】:

  • 不要关闭它?或者使用MemoryStream.ToArray 并创建一个新流。
  • 开发;如果您已正式关闭流,则无法重新打开它 - 但也许它可能有助于解释您正在管理的内容以及为什么需要首先关闭流。最终,您想通过流实现什么目标?
  • @RussClarke 这通常是因为某些第三方库“有用地”为您关闭了您的流。不幸的是,这并不少见。

标签: c#


【解决方案1】:

如何重新打开已关闭的内存流?

您无法重新打开该信息流。如果您需要“重置”流,只需为其分配一个新实例:

memoryStream = new MemoryStream();

【讨论】:

  • 但是如何重用已关闭的内存流?
  • 正如里德所说,你不能。如果您以后需要它,请不要关闭它。如果您无法更改已关闭的事实,则必须创建一个新的。
  • 确实,但正如您在问题中暗示的那样,您也许可以使用 Flush 和 Position 来代替关闭流?
【解决方案2】:

您可以克隆原始版本,然后使用克隆版本,即使原始版本已关闭。即使最初创建的容量为 1000,ToArray() 也会返回一个 2 元素数组。另一方面,ToBuffer() 为您提供整个缓冲区,这是您不想要的。

MemoryStream original = new MemoryStream(1000);
original.WriteByte(4);
original.WriteByte(5);

MemoryStream dolly = new MemoryStream(original.ToArray());
dolly.Seek(0, SeekOrigin.Begin);

【讨论】:

  • 克隆是否复制缓冲区?或者只是指向相同的支持字节[]?我正在尝试从关闭的 MemoryStream 中获取 .Length (愚蠢的 API 认为编写 关闭流...)
  • 它复制缓冲区。在此处查看 ToArray():referencesource.microsoft.com/#mscorlib/system/io/…
【解决方案3】:

试试这个:

memoryStream = new MemoryStream(memoryStream.ToArray());

【讨论】:

    【解决方案4】:

    这是一个古老而古老的问题,但我正在对以下事实做出反应,即接受的答案并不是真正有用,并且投票率最高的答案说使用 .ToArray() 比 .GetBuffer() 更好。我认为在许多,也许是大多数情况下,使用 .GetBuffer() 比使用 .ToArray() 好得多。

    这是一个内存流关闭问题的示例,尽管您希望继续使用它:

      /// <summary>
      /// Method that gets called by ManagedResource.WriteData() in project CodeAnalysis during code 
      /// emitting to get the data for an embedded resource file.
      /// </summary>
      /// <param name="resourceFullFilename">full path and filename for resource file to embed</param>
      /// <returns>MemoryStream containing .resource file data - caller will dispose it</returns>
      private static MemoryStream ProvideResourceData(string resourceFullFilename)
      {
         MemoryStream shortLivedBackingStream = new MemoryStream();
         using (ResourceWriter resourceWriter = new ResourceWriter(shortLivedBackingStream))
         {
            using (ResXResourceReader resourceReader = new ResXResourceReader(resourceFullFilename))
            {
               IDictionaryEnumerator dictionaryEnumerator = resourceReader.GetEnumerator();
               while (dictionaryEnumerator.MoveNext())
               {
                  string resourceKey = dictionaryEnumerator.Key as string;
                  if (resourceKey != null)  // Should not be possible
                     resourceWriter.AddResource(resourceKey, dictionaryEnumerator.Value);
               }
            }
         }
    
         return new MemoryStream(shortLivedBackingStream.GetBuffer());
      }
    

    ResourceWriter 类需要一个支持流,所以我给它一个新创建的内存流。但是当不再需要ResourceWriter 时,它会关闭支持流。然后我基于支持流的缓冲区创建一个新的MemoryStream,即使它已关闭,它也可以正常工作。

    在这种情况下,我碰巧知道调用程序将使用提供的内存流将数据复制到另一个缓冲区,然后立即关闭内存流。所以不需要新建字节数组,新建字节数组有性能优势。

    感谢@JoshVarty 展示了如何避免MemoryStream 在此处关闭的问题:https://github.com/dotnet/roslyn/issues/7791

    【讨论】:

    • “在这种情况下,我碰巧知道调用程序将...” - 但这有点代码味道,不是吗?来维护这种方法的其他人可能不具备这种知识。理想情况下,该方法应该独立工作并且像黑匣子一样工作。有时,说起来容易做起来难:)。
    猜你喜欢
    • 2011-12-27
    • 2012-06-11
    • 2017-08-09
    • 2018-10-14
    • 2011-01-20
    • 2016-02-06
    • 2021-12-21
    • 2017-01-12
    • 1970-01-01
    相关资源
    最近更新 更多