C# 有没有办法关闭StreamWriter而不关闭其基本流?

C# 有没有办法关闭StreamWriter而不关闭其基本流?,c#,stream,dispose,C#,Stream,Dispose,我的根本问题是,当在StreamWriter上使用调用Dispose时,它也会处理基本流(与关闭的问题相同) 我有一个解决方法,但正如您所看到的,它涉及到复制流。有没有办法不用复制流就可以做到这一点 其目的是将字符串(最初从数据库读取)的内容放入流中,以便第三方组件可以读取该流。 NB:我无法更改第三方组件 public System.IO.Stream CreateStream(string value) { var baseStream = new System.IO.MemoryS

我的根本问题是,当
StreamWriter
上使用
调用
Dispose
时,它也会处理
基本流
(与
关闭
的问题相同)

我有一个解决方法,但正如您所看到的,它涉及到复制流。有没有办法不用复制流就可以做到这一点

其目的是将字符串(最初从数据库读取)的内容放入流中,以便第三方组件可以读取该流。
NB:我无法更改第三方组件

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

如果您使用的是.NET Framework 4.5或更高版本,则会出现以下问题

在.NET Framework 4.5之前的早期版本中,
StreamWriter
假定它拥有流。选项:

  • 不要处理
    StreamWriter
    ;把它冲洗一下
  • 创建一个流包装器,它忽略对
    Close
    /
    Dispose
    的调用,但代理所有其他调用。我有一个在中的实现,如果你想从那里得到它的话

只需不调用
StreamWriter上的
Dispose
。此类是可丢弃的原因不是因为它持有非托管资源,而是允许处置本身可能持有非托管资源的流。如果基础流的生命周期在别处处理,则无需处理写入程序。

您需要创建StreamWriter的后代并重写其dispose方法,通过始终将false传递给disposing参数,它将强制流写入程序不关闭,StreamWriter只在close方法中调用dispose,因此无需重写它(当然,如果需要,可以添加所有构造函数,我只有一个):


内存流具有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;
}

.NET 4.5为此提供了一种新方法:

公共StreamWriter(
溪流,
编码,
int缓冲区大小,
布尔叶开
)


@Marc,调用
Flush
是否会在缓冲数据的情况下执行此任务?很好,但一旦我们退出CreateStream,StreamWrtier就可以收集,迫使第三方读卡器与GC竞争,这不是我想要的情况。还是我遗漏了什么?@BinaryWorrier:不,没有竞争条件:StreamWriter没有终结器(而且确实不应该)。@BinaryWorrier:如果您直接拥有资源,您应该只有终结器。在这种情况下,StreamWriter应该假设流将在需要时自行清理。StreamWriter的“close”方法似乎也会关闭并处理流。因此必须刷新,但不能关闭或处理streamwriter,因此它不会关闭流,这相当于处理流。这里的API提供了太多的“帮助”。这是一个类似的问题:我是用来自WebRequest的流来做这件事的,有趣的是,如果编码是ASCII而不是UTF8,您可以关闭它。tofutim,我把我的编码为ASCII,它仍然处理底层流。我相信这并不像你想象的那样。
disposing
标志是的一部分。始终将
false
传递给基类的
Dispose(bool)
方法基本上是向
StreamWriter
发出信号,表明它是从终结器调用的(显式调用
Dispose()
时不是这样),因此不应该访问任何托管对象。这就是它不会处理基流的原因。然而,你实现这一目标的方式是一种黑客行为;一开始不调用
Dispose
会简单得多!这就是赛门铁克的真实想法,除了从头开始重写流媒体之外,你所做的任何事情都将是一次黑客攻击。当然,您根本不能调用base.Dispose(false),但在功能上没有区别,我喜欢我的示例的清晰性。但是,请记住这一点,StreamWriter类的未来版本可能不仅仅是在处理流时关闭流,因此调用dispose(false)future Proof也会对其进行验证。但每个人都有自己的。另一种方法是创建自己的流包装器,其中包含另一个流,其中Close方法不关闭底层流,而只是什么也不做,这不是一种黑客行为,而是一项更大的工作。惊人的时机:我正要提出同样的建议(装饰器类,可能命名为
OwnedStream
,它忽略
Dispose(bool)
Close
).是的,上面的代码是我如何为一个快速而肮脏的方法完成它的,但是如果我正在制作一个商业应用程序或对我来说真正重要的东西,我会使用流包装器类正确地完成它。我个人认为微软在这里犯了一个错误,streamwriter应该有一个布尔属性来关闭底层流instead、 但是我不在微软工作,所以他们做他们喜欢做的事情。我猜:DThanks mate!我不知道这一点,如果有什么原因的话,这将是我开始瞄准.NET 4.5的一个很好的理由!遗憾的是,没有不需要设置缓冲大小的重载。我对默认值很满意。我必须自己通过它。不是世界末日。数据fault
bufferSize
1024
。显然,4.5重载不是经过深思熟虑的让步——重载要求缓冲区大小,不能为0或null。在内部,我知道128个字符是最小大小,所以我只是将其设置为1。否则,这个“功能”让我很高兴。有没有办法将其设置为
leaveOpenStreamWriter
后的code>参数?@c0000fd:No
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;
}