MemoryStream - 无法访问已关闭的流
Posted
技术标签:
【中文标题】MemoryStream - 无法访问已关闭的流【英文标题】:MemoryStream - Cannot access a closed Stream 【发布时间】:2012-06-11 16:06:31 【问题描述】:嗨,为什么 using (var sw = new StreamWriter(ms))
返回 Cannot access a closed Stream
exception
。 Memory Stream
位于此代码之上。
using (var ms = new MemoryStream())
using (var sw = new StreamWriter(ms))
sw.WriteLine("data");
sw.WriteLine("data 2");
ms.Position = 0;
using (var sr = new StreamReader(ms))
Console.WriteLine(sr.ReadToEnd());
//error here
修复它的最佳方法是什么? 谢谢
【问题讨论】:
这可能是因为您正在从同一个 MemoryStream 创建 StreamWriter 和 StreamReader。您可以尝试使用两种不同的 MemoryStream:一种用于读取器,一种用于写入器。 ***.com/questions/2331675/cannot-access-closed-stream的可能重复 在某些情况下,解决方案可以基于在关闭的内存流上使用MemoryStream.GetBuffer()
创建一个新的MemoryStream
。见这里:***.com/a/50671919/253938
【参考方案1】:
这是因为StreamReader
在被处理时会自动关闭底层流。 using
语句会自动执行此操作。
但是,您正在使用的 StreamWriter
仍在尝试处理流(此外,作者的 using
语句现在正在尝试处理 StreamWriter
,然后尝试关闭流)。
解决此问题的最佳方法是:不要使用using
,也不要丢弃StreamReader
和StreamWriter
。见this question。
using (var ms = new MemoryStream())
var sw = new StreamWriter(ms);
var sr = new StreamReader(ms);
sw.WriteLine("data");
sw.WriteLine("data 2");
ms.Position = 0;
Console.WriteLine(sr.ReadToEnd());
如果您对 sw
和 sr
被垃圾收集而没有在您的代码中处理(按照建议)感到难过,您可以这样做:
StreamWriter sw = null;
StreamReader sr = null;
try
using (var ms = new MemoryStream())
sw = new StreamWriter(ms);
sr = new StreamReader(ms);
sw.WriteLine("data");
sw.WriteLine("data 2");
ms.Position = 0;
Console.WriteLine(sr.ReadToEnd());
finally
if (sw != null) sw.Dispose();
if (sr != null) sr.Dispose();
【讨论】:
毫无疑问,我假设为什么 OP 会问“修复它的最佳方法是什么?” 如何关闭 var sw = new StreamWriter(ms); var sr = 新的 StreamReader(ms); ? 您无需担心它们。我引用了我链接的问题中已接受的答案:如果您需要直接使用底层流,您应该可以让 StreamReader 超出范围。只需确保在适当的时候手动处理底层流。 换句话说:虽然没有明确处理读取器和写入器,但它们最终将被垃圾收集。但我会再次编辑以提供另一种可能的解决方案。【参考方案2】:从 .net45 开始,您可以使用 StreamWriter
的 LeaveOpen
构造函数参数并仍然使用 using
语句。示例:
using (var ms = new MemoryStream())
using (var sw = new StreamWriter(ms, leaveOpen:true))
sw.WriteLine("data");
sw.WriteLine("data 2");
ms.Position = 0;
using (var sr = new StreamReader(ms))
Console.WriteLine(sr.ReadToEnd());
【讨论】:
+1 用于提及,也可以不使用“using”-Statement。 (我的底层 MemoryStream 需要保持活力)和微软的 -1 迫使我进入 那个 丑陋的 ctor。 ^^ @Jan 你可以使用new StreamWriter(ms, leaveOpen:true)
,我想这不那么丑了【参考方案3】:
当您的StreamReader
的using()
结束时,它正在处理对象并关闭您的StreamWriter
仍在尝试使用的流。
【讨论】:
毫无疑问,我假设为什么 OP 会问“修复它的最佳方法是什么?”【参考方案4】:问题是这个块:
using (var sr = new StreamReader(ms))
Console.WriteLine(sr.ReadToEnd());
当StreamReader
关闭时(离开使用后),它也会关闭它的底层流,所以现在MemoryStream
已关闭。当StreamWriter
关闭时,它会尝试将所有内容刷新到MemoryStream
,但它已关闭。
您应该考虑不要将 StreamReader
放在 using 块中。
【讨论】:
【参考方案5】:当它从 using 语句中退出时,Dispose
方法将被调用自动关闭流
试试下面的:
using (var ms = new MemoryStream())
var sw = new StreamWriter(ms);
sw.WriteLine("data");
sw.WriteLine("data 2");
ms.Position = 0;
using (var sr = new StreamReader(ms))
Console.WriteLine(sr.ReadToEnd());
【讨论】:
【参考方案6】:在我的情况下(诚然非常神秘,不太可能经常复制),这是导致问题的原因(此代码与使用 iTextSharp 生成 PDF 相关):
PdfPTable tblDuckbilledPlatypi = new PdfPTable(3);
float[] DuckbilledPlatypiRowWidths = new float[] 42f, 76f ;
tblDuckbilledPlatypi.SetWidths(DuckbilledPlatypiRowWidths);
显然,声明一个 3 单元格/列的表,然后只为宽度设置两个 val 是导致问题的原因。一旦我将“PdfPTable(3)”更改为“PdfPTable(2)”,问题就出现在对流烤箱上。
【讨论】:
这应该是另一个问题+答案。它与OP问题无关。虽然它可能对iTextSharp
用户非常有用,但您向他人提供帮助的方式是错误的(将其放入只有类似异常文本的随机问题?)以上是关于MemoryStream - 无法访问已关闭的流的主要内容,如果未能解决你的问题,请参考以下文章
从 Azure 存储流式传输 blob - 无法访问已关闭的流
Azure.Storage.Blobs.ServiceRestClient.GetUserDelegationKey:System.ObjectDisposedException:无法访问已关闭的流