我遇到使用多个流通过http下载压缩文件的情况。为此,我需要使用多个流。即获取Web响应流,读入二进制读取器流,使用二进制写入器流写入内存流等。
由于这一切都有点复杂和令人讨厌,我已将所有内容拆分为小函数以使其读起来更好一些,但是我对从公共DownloadCsvReport
函数调用的readStreamIntoMemoryStream
函数有一些证明,请参见下文:
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;
}
}
}
我不确定的是,当公共方法失去作用域时,MemoryStream
是否会释放来自私有函数的BinaryWriter
和BinaryReader
流?如果不是,并且我将这些流包装在私有方法中的 using 语句中,那么当我尝试在公共方法中访问MemoryStream
时,它不会引发异常吗?
这是 .NET Framework 中的一个设计缺陷,该缺陷已从 .NET 4.5 开始修复,您可以在其中使用BinaryWriter
和BinaryReader
构造函数的重载,这些构造函数允许您在释放流后保持打开状态。
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;
}
我不确定的是,当公共方法失去作用域时,来自私有函数的 BinaryWriter 和 BinaryReader 流是否会被释放?
问题是,BinaryWriter
和BinaryReader
不是流。
它们作用于底层流,在您的情况下,底层流是memoryStream
。所以,只要你关闭你的memoryStream
和外responseStream
,一切都很好。
编辑:
事实上,看看他们的源代码:
protected virtual void Dispose(bool disposing)
{
if (disposing)
OutStream.Close();
}
如您所见,它所做的只是在底层流上调用Dispose
。您当前的代码已经这样做了 - 因此无需处理编写器/读取器。这将是多余的。