有啥方法可以在不关闭其 BaseStream 的情况下关闭 StreamWriter?
Posted
技术标签:
【中文标题】有啥方法可以在不关闭其 BaseStream 的情况下关闭 StreamWriter?【英文标题】:Is there any way to close a StreamWriter without closing its BaseStream?有什么方法可以在不关闭其 BaseStream 的情况下关闭 StreamWriter? 【发布时间】:2011-02-09 15:32:17 【问题描述】:我的根本问题是,当using
在StreamWriter
上调用Dispose
时,它也会处理BaseStream
(与Close
相同的问题)。
我有一个解决方法,但正如您所见,它涉及复制流。有没有办法在不复制流的情况下做到这一点?
这样做的目的是将字符串的内容(最初从数据库中读取)获取到流中,以便第三方组件可以读取流。注意:我无法更改第三方组件。
public System.IO.Stream CreateStream(string value)
var baseStream = new System.IO.MemoryStream();
var baseCopy = new System.IO.MemoryStream();
using (var writer = new System.IO.StreamWriter(baseStream, System.Text.Encoding.UTF8))
writer.Write(value);
writer.Flush();
baseStream.WriteTo(baseCopy);
baseCopy.Seek(0, System.IO.SeekOrigin.Begin);
return baseCopy;
用作
public void Noddy()
System.IO.Stream myStream = CreateStream("The contents of this string are unimportant");
My3rdPartyComponent.ReadFromStream(myStream);
理想情况下,我正在寻找一种名为BreakAssociationWithBaseStream
的虚构方法,例如
public System.IO.Stream CreateStream_Alternate(string value)
var baseStream = new System.IO.MemoryStream();
using (var writer = new System.IO.StreamWriter(baseStream, System.Text.Encoding.UTF8))
writer.Write(value);
writer.Flush();
writer.BreakAssociationWithBaseStream();
return baseStream;
【问题讨论】:
这是一个类似的问题:***.com/questions/2620851 我正在使用来自 WebRequest 的流来执行此操作,有趣的是,如果编码是 ASCII 而不是 UTF8,您可以关闭它。很奇怪。 tofutim,我已经将我的编码为 ASCII,它仍然处理底层流.. 【参考方案1】:如果您使用的是 .NET Framework 4.5 或更高版本,则有一个StreamWriter overload using which you can ask the base stream to be left open when the writer is closed。
在 .NET Framework 4.5 之前的早期版本中,StreamWriter
假定它拥有流。选项:
StreamWriter
;冲洗一下。
创建一个流包装器,它会忽略对Close
/Dispose
的调用,但会代理其他所有内容。我在MiscUtil 中有一个实现,如果你想从那里获取它。
【讨论】:
显然 4.5 的重载是一个没有经过深思熟虑的让步——重载需要缓冲区大小,它不能为 0 也不能为空。在内部我知道 128 个字符是最小大小,所以我将其设置为 1。否则这个“功能”让我很高兴。 有没有办法在创建StreamWriter
之后设置leaveOpen
参数?
@c00000fd:我不知道。
@Yepeekai:“如果我将流传递给子方法并且该子方法创建 StreamWriter,它将在该子方法执行结束时被释放”不,这根本不是真的.只有在有人调用Dispose
时才会处理它。方法结束不会自动执行此操作。如果它有一个终结器,它可能会在以后最终确定,但这不是一回事 - 仍然不清楚你预期的危险是什么。如果您认为从方法中返回 StreamWriter
是不安全的,因为它可能会被 GC 自动释放,那是不正确的。
@Yepeekai:IIRC,StreamWriter
没有终结器 - 正是出于这个原因,我不希望它有。【参考方案2】:
.NET 4.5 有一个新方法:
StreamWriter(Stream, Encoding, Int32, Boolean)
public StreamWriter(
Stream stream,
Encoding encoding,
int bufferSize,
bool leaveOpen
)
【讨论】:
谢谢伙计!不知道这一点,如果有什么是我开始瞄准 .NET 4.5 的好理由! 遗憾的是,没有不需要设置 bufferSize 的重载。我对那里的默认设置很满意。我必须自己通过。不是世界末日。 默认的bufferSize
是1024
。 Details are here.【参考方案3】:
内存流有一个 ToArray 属性,即使在流关闭时也可以使用该属性。 To Array 将流内容写入字节数组,而不考虑 Position 属性。 您可以根据您写入的流创建一个新流。
public System.IO.Stream CreateStream(string value)
var baseStream = new System.IO.MemoryStream();
var baseCopy = new System.IO.MemoryStream();
using (var writer = new System.IO.StreamWriter(baseStream, System.Text.Encoding.UTF8))
writer.Write(value);
writer.Flush();
baseStream.WriteTo(baseCopy);
var returnStream = new System.IO.MemoryStream( baseCopy.ToArray());
return returnStream;
【讨论】:
这是否正确地将返回的数组限制为内容大小?因为Stream.Position
在被释放后不能被调用。【参考方案4】:
你需要创建 StreamWriter 的后代并重写它的 dispose 方法,通过始终将 false 传递给 disposing 参数,它将强制流写入器不关闭,StreamWriter 只是在 close 方法中调用 dispose,所以有不需要覆盖它(当然你可以添加所有的构造函数,我只有一个):
public class NoCloseStreamWriter : StreamWriter
public NoCloseStreamWriter(Stream stream, Encoding encoding)
: base(stream, encoding)
protected override void Dispose(bool disposing)
base.Dispose(false);
【讨论】:
我相信这不会像您认为的那样。disposing
标志是the IDisposable
pattern 的一部分。始终将false
传递给基类的Dispose(bool)
方法基本上向StreamWriter
发出信号,表明它正在从终结器调用(当您显式调用Dispose()
时并非如此),因此不应访问任何托管对象。 这 是它不会处理基本流的原因。但是,您实现这一目标的方式是一种技巧。一开始就不叫Dispose
会简单得多!
这就是赛门铁克,除了完全从头开始重写流媒体之外,您所做的任何事情都将是一种黑客行为。当然,您可以根本不调用 base.Dispose(false),但不会有功能差异,我喜欢我的示例的清晰性。但是,请记住这一点,StreamWriter 类的未来版本可能不仅仅是在处理流时关闭流,因此调用 dispose(false) 也可以证明它。但对每个人来说都是他自己的。
另一种方法是创建自己的流包装器,其中包含另一个流,其中 Close 方法不执行任何操作而不是关闭底层流,这不是一个 hack,而是一个更多的工作.
惊人的时机:我正要建议同样的事情(装饰类,可能命名为OwnedStream
,忽略Dispose(bool)
和Close
)。
是的,上面的代码是我如何实现快速而肮脏的方法,但如果我正在制作商业应用程序或对我来说真正重要的东西,我会使用 Stream 包装器类正确地完成它.就我个人而言,我认为微软在这里犯了一个错误,streamwriter 应该有一个布尔属性来关闭底层流,但是我不在微软工作,所以我猜他们会做他们喜欢做的事情:D【参考方案5】:
不要在StreamWriter
上拨打Dispose
。这个类是一次性的原因不是因为它拥有非托管资源,而是允许处理本身可以拥有非托管资源的流。如果底层流的生命周期在其他地方处理,则无需处置 writer。
【讨论】:
@Marc,不会调用Flush
来完成这项工作,以防它缓冲数据?
很好,但是一旦我们退出 CreateStream,StreamWrtier 是可收集的,迫使第三方阅读器与 GC 竞争,这不是我想要留在的情况。或者我错过了什么?
@BinaryWorrier:不,没有竞争条件:StreamWriter 没有终结器(实际上不应该)。
@Binary Worrier:如果你直接拥有资源,你应该只有一个终结器。在这种情况下,StreamWriter 应该假设 Stream 会在需要时自行清理。
StreamWriter 的 'close' 方法似乎也关闭并处理了流。因此,必须刷新,但不能关闭或处置流写入器,因此它不会关闭流,这相当于处置流。这里的 API 提供了太多“帮助”。以上是关于有啥方法可以在不关闭其 BaseStream 的情况下关闭 StreamWriter?的主要内容,如果未能解决你的问题,请参考以下文章
有啥方法可以在不重新加载的情况下更改标头 URL? [复制]
有啥方法可以在不使用 getImageData() 的情况下在 JavaScript 中找到像素的颜色?
有啥方法可以在不将 CIImage 转换为 UIImage 或 CGImage 的情况下将 CIImage 转换为 NSData?