当使用从其他Stream创建的Stream时,如何使用语句范围?

时间:2014-02-24 09:25:05

标签: c# .net stream using

我遇到的情况是我使用多个流来通过http下载压缩文件。为此,我需要使用多个流。即获取Web响应流,读入二进制读取器流,使用二进制写入器流写入内存流等等。

因为它有点复杂和令人讨厌我已经将所有内容分成小函数以使它读得更好,但我对readStreamIntoMemoryStream函数有一点问题我是从公共DownloadCsvReport函数调用,请参见下文:

public IEnumerable<string> DownloadCsvReport(string reportDownloadUrl)
{
    using (Stream responseStream = creatDownloadWebRequest(reportDownloadUrl))
    using (MemoryStream memoryStream = readStreamIntoMemoryStream(responseStream))
    {
        setMemoryStreamToBegining(memoryStream);
        ZipEntry zipEntry = getZippedFileFromMemoryStream(memoryStream);
        return convertZippedFileToCsvRows(zipEntry);
    }
}

private MemoryStream readStreamIntoMemoryStream(Stream webResponseStream)
{
    var memoryStream = new MemoryStream();
    var binaryWriter = new BinaryWriter(memoryStream);
    var binaryReader = new BinaryReader(webResponseStream);

    while (true)
    {
        byte[] buffer = binaryReader.ReadBytes(BufferSize);
        binaryWriter.Write(buffer);

        if (buffer.Length != BufferSize)
        {
            return memoryStream;
        }
    }
}

我不确定的是,当BinaryWriter是公共方法失去范围时,来自私有函数的BinaryReaderMemoryStream流是否会被处理掉?如果没有,我将这些流包装在私有方法中的using语句中,当我尝试访问公共方法中的MemoryStream时,是否会抛出异常?

2 个答案:

答案 0 :(得分:2)

这是.NET Framework中的一个设计缺陷,自.NET 4.5开始修复,您可以使用BinaryWriterBinaryReader构造函数的重载,让您打开流处理完毕后。

var memoryStream = new MemoryStream();
var encoding = new UTF8Encoding(false, true);
using (var binaryWriter = new BinaryWriter(memoryStream, encoding, true))
using (var binaryReader = new BinaryReader(webResponseStream, encoding, true))
{
    // ...
    return memoryStream;
}

编辑:如果您使用的是.NET 4(或更早版本),则可以使用Jon Skeet的MiscUtil库中的NonClosingStreamWrapper类:

var memoryStream = new MemoryStream();
using (var memoryStreamWrapper = new NonClosingStreamWrapper(memoryStream))
using (var webResponseStreamWrapper = new NonClosingStreamWrapper(webResponseStream))
using (var binaryWriter = new BinaryWriter(memoryStreamWrapper))
using (var binaryReader = new BinaryReader(webResponseStreamWrapper))
{
    // ...
    return memoryStream;
}

答案 1 :(得分:1)

  

我不确定的是,当MemoryStream是公共方法失去范围时,来自私有函数的BinaryWriter和BinaryReader流是否会被处理掉?

问题是,BinaryWriterBinaryReader 不是流。

它们对基础流起作用,在您的情况下,它是memoryStream。 因此,只要您关闭memoryStream和外responseStream,一切都会好的。

修改

事实上,看看他们的source code

protected virtual void Dispose(bool disposing)
{
    if (disposing)
        OutStream.Close();
}

如您所见,它只是在底层流上调用Dispose。您当前的代码已经这样做了 - 所以不需要处理编写器/阅读器。这将是多余的。