有没有办法在不关闭BaseStream的情况下关闭StreamWriter?

Bin*_*ier 107 c# dispose stream

我的根本问题是,当using调用Disposea时StreamWriter,它也会处理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;
}
Run Code Online (Sandbox Code Playgroud)

用作

public void Noddy()
{
    System.IO.Stream myStream = CreateStream("The contents of this string are unimportant");
    My3rdPartyComponent.ReadFromStream(myStream);
}
Run Code Online (Sandbox Code Playgroud)

理想情况下,我正在寻找一个名为的假想方法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;
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 108

如果您使用的是.NET Framework 4.5或更高版本,则会有一个StreamWriter重载,使用该重载可以在编写器关闭时让基本流保持打开状态.

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

  • 不要丢弃StreamWriter; 只是冲洗它.
  • 创建一个流包装器,忽略对Close/的调用,Dispose但代理其他所有内容.我在MiscUtil中有一个实现,如果你想从那里抓取它.

  • 显然4.5过载是一个没有考虑过的让步 - 过载需要缓冲区大小,它不能是0也不是null.在内部,我知道128个字符是最小尺寸,所以我只需将其设置为1.否则这个"功能"让我开心. (15认同)

mal*_*ger 41

.NET 4.5获得了新的方法!

http://msdn.microsoft.com/EN-US/library/gg712853(v=VS.110,d=hv.2).aspx

public StreamWriter(
    Stream stream,
    Encoding encoding,
    int bufferSize,
    bool leaveOpen
)
Run Code Online (Sandbox Code Playgroud)

  • 遗憾的是没有重载不需要设置bufferSize.我对那里的默认值感到满意.我必须自己通过它.不是世界末日. (20认同)
  • 默认的`bufferSize`是'1024`.[详情在这里](/sf/answers/2058960081/). (3认同)

Dar*_*rov 32

根本就不要打电话DisposeStreamWriter.这个类是一次性的原因不是因为它拥有非托管资源,而是允许处理本身可能拥有非托管资源的流.如果底层流的生命在其他地方处理,则无需处理编写器.

  • @BinaryWorrier:不,没有竞争条件:StreamWriter没有终结器(实际上不应该). (9认同)
  • @Binary Worrier:如果你*直接*拥有资源,你应该只有一个终结者.在这种情况下,StreamWriter应该假设Stream会在需要时自行清理. (9认同)
  • 很好,但是一旦我们退出CreateStream,StreamWrtier就是可收集的,迫使第三方读者与GC竞争,这不是我想要留下的情况.或者我错过了什么? (3认同)
  • @Marc,如果缓冲数据,不会调用`Flush`来做这项工作? (2认同)
  • StreamWriter 的“关闭”方法似乎也关闭并处理了流。所以必须刷新,但不能关闭或处置流写入器,因此它不会关闭流,这相当于处置流。这里来自 API 的“帮助”太多了。 (2认同)
  • @JonSkeet 但_知道_`StreamWriter` 没有终结器是一个实现细节 - 我不应该知道或依赖它。 (2认同)

小智 5

内存流具有ToArray属性,即使在关闭流时也可以使用该属性.无论Position属性如何,To Array都将流内容写入字节数组.您可以根据您编写的流创建新流.

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;
}
Run Code Online (Sandbox Code Playgroud)