我有以下代码:
byte[] fileBytes = null;
using (var wc = new System.Net.WebClient())
{
fileBytes = wc.DownloadData(filename);
}
filename是一个包含“file://example.com/Media-Data/thisisabigmovie.wmv”之类的网址
现在我的客户似乎有很大的文件会引发以下错误:
System.OutOfMemoryException:
at System.Net.ScatterGatherBuffers.AllocateMemoryChunk(Int32 newSize)
at System.Net.ScatterGatherBuffers.Write(Byte[] buffer, Int32 offset, Int32 count)
at System.Net.WebClient.DownloadBitsState.RetrieveBytes(Int32& bytesRetrieved)
at System.Net.WebClient.DownloadBits(WebRequest request, Stream writeStream, CompletionDelegate completionDelegate, AsyncOperation asyncOp)
at System.Net.WebClient.DownloadDataInternal(Uri address, WebRequest& request)
at System.Net.WebClient.DownloadData(Uri address)
at System.Net.WebClient.DownloadData(String address)
有没有办法解决这个问题?也许以“chunks”下载文件?
答案 0 :(得分:7)
不要使用DownloadData
,因为它会在Byte[]
中返回响应,该响应将达到.NET的2GB最大对象大小限制。
您应该使用HttpClient
或原始HttpWebRequest
对象而不是WebClient
,并将响应流直接传输到磁盘上的FileStream
左右。使用CopyToAsync
方法:
using( Stream responseStream = response.GetResponseStream() )
using( FileStream fileStream = new FileStream( "tempFile.bin" ) )
{
await responseStream.CopyToAsync( fileStream ).ConfigureAwait(false);
}
答案 1 :(得分:2)
您打算在下载后对该文件执行什么操作?如果您立即将其保存到磁盘,则只需使用WebClient的DownloadFile
方法而不是DownloadData
。正如您猜测的那样,DownloadFile
在内部使用FileStream
并以块的形式保存到磁盘:
using (var wc = new System.Net.WebClient())
{
wc.DownloadFile(remoteUri, localFilename);
}
如果您需要处理字节而不仅仅是保存它们,您应该使用基于流的方法将数据作为流来获取 - 这意味着您在它到达时处理它,而不是在您将数据全部存储之后在记忆中。为此,WebClient不会帮助您,您应该使用较新的HttpClient
或较旧的,更低级别的HttpWebRequest
var response = await new HttpClient().GetAsync(remoteUrl);
var dataStream = await response.Content.ReadAsStreamAsync();
或 var request =(HttpWebRequest)WebRequest.Create(remoteUrl); var response = request.GetResponse(); var dataStream = response.GetResponseStream();