我正在尝试从公共URL下载一个大文件。一开始似乎工作正常,但有 1/10 的计算机会超时。 我最初尝试使用WebClient.DownloadFileAsync
,但由于它永远无法完成,我回退到使用WebRequest.Create
并直接读取响应流。
我第一次使用WebRequest.Create
的版本发现与WebClient.DownloadFileAsync
相同的问题。 操作超时,文件未完成。
我的下一个版本增加了重试功能以在下载超时时重新尝试。这里变得奇怪了。下载确实最终完成,只需重试即可完成最后的7092字节。 因此,文件的大小完全相同,但该文件已损坏并且与源文件不同。 现在我希望损坏在最后的7092个字节中,但事实并非如此。
使用BeyondCompare,我发现损坏的文件中缺少2个字节块,共计缺少7092个字节!这些缺失的字节位于1CA49FF0
和1E31F380
处,远远在下载超时并重新启动之前。
这里可能出了什么问题?有没有提示进一步追踪此问题的方法?
以下是相关代码。
public void DownloadFile(string sourceUri, string destinationPath)
{
//roughly based on: https://dev59.com/OXE95IYBdhLWcg3wi-Yc
//not using WebClient.DownloadFileAsync as it seems to stall out on large files rarely for unknown reasons.
using (var fileStream = File.Open(destinationPath, FileMode.Create, FileAccess.Write, FileShare.Read))
{
long totalBytesToReceive = 0;
long totalBytesReceived = 0;
int attemptCount = 0;
bool isFinished = false;
while (!isFinished)
{
attemptCount += 1;
if (attemptCount > 10)
{
throw new InvalidOperationException("Too many attempts to download. Aborting.");
}
try
{
var request = (HttpWebRequest)WebRequest.Create(sourceUri);
request.Proxy = null;//https://dev59.com/J3RA5IYBdhLWcg3w_DLF#935728
_log.AddInformation("Request #{0}.", attemptCount);
//continue downloading from last attempt.
if (totalBytesReceived != 0)
{
_log.AddInformation("Request resuming with range: {0} , {1}", totalBytesReceived, totalBytesToReceive);
request.AddRange(totalBytesReceived, totalBytesToReceive);
}
using (var response = request.GetResponse())
{
_log.AddInformation("Received response. ContentLength={0} , ContentType={1}", response.ContentLength, response.ContentType);
if (totalBytesToReceive == 0)
{
totalBytesToReceive = response.ContentLength;
}
using (var responseStream = response.GetResponseStream())
{
_log.AddInformation("Beginning read of response stream.");
var buffer = new byte[4096];
int bytesRead = responseStream.Read(buffer, 0, buffer.Length);
while (bytesRead > 0)
{
fileStream.Write(buffer, 0, bytesRead);
totalBytesReceived += bytesRead;
bytesRead = responseStream.Read(buffer, 0, buffer.Length);
}
_log.AddInformation("Finished read of response stream.");
}
}
_log.AddInformation("Finished downloading file.");
isFinished = true;
}
catch (Exception ex)
{
_log.AddInformation("Response raised exception ({0}). {1}", ex.GetType(), ex.Message);
}
}
}
}
以下是来自损坏下载的日志输出:
Request #1.
Received response. ContentLength=939302925 , ContentType=application/zip
Beginning read of response stream.
Response raised exception (System.Net.WebException). The operation has timed out.
Request #2.
Request resuming with range: 939295833 , 939302925
Received response. ContentLength=7092 , ContentType=application/zip
Beginning read of response stream.
Finished read of response stream.
Finished downloading file.
DownloadFile
方法解决了我遇到的一个完全无关的问题,给您点个赞。 - cod3monk3y