我正在尝试实现一些从URL下载文件的功能。但是,如果文件花费的时间超过30秒,我想取消下载,或者让它超时。
我已经尝试重写WebClient类来实现超时,但无论我将超时设置为什么值,它都不会超时!以下是我尝试过的代码,found in another stackoverflow answer:
using System;
using System.Net;
public class WebDownload : WebClient
{
/// <summary>
/// Time in milliseconds
/// </summary>
public int Timeout { get; set; }
public WebDownload() : this(60000) { }
public WebDownload(int timeout)
{
this.Timeout = timeout;
}
protected override WebRequest GetWebRequest(Uri address)
{
var request = base.GetWebRequest(address);
if (request != null)
{
request.Timeout = this.Timeout;
}
return request;
}
}
然后,使用:
调用 WebDownload webClient = new WebDownload(20000);
try
{
webClient.DownloadFile(url, tmpFile);
}
catch {
//throw error
}
我也尝试使用WebRequest方法下载文件,并使用Timeout和ReadWriteTimeout属性,但没有骰子。这个有是一个非常常见的用例。任何帮助表示赞赏。谢谢!
答案 0 :(得分:1)
如何创建扩展方法?
WebClient wc = new WebClient();
wc.DownloadFileWithTimeout(url, filename, 20000);
public static class SOExtensions
{
public static void DownloadFileWithTimeout(this WebClient wc, string url, string file, int timeout)
{
var tcs = new TaskCompletionSource<bool>();
var bgTask = Task.Factory.StartNew(() =>
{
wc.DownloadFileTaskAsync(url, file).Wait();
tcs.TrySetResult(true);
});
if (!bgTask.Wait(timeout))
{
wc.CancelAsync();
throw new TimeoutException("Timed out while downloading \"" + url + "\"");
}
}
}
答案 1 :(得分:0)
您实施的超时涉及获取响应,但不包含包含所有数据的ResponseStream,并且通常需要更多时间来实现。例如,获得响应通常需要1秒以下,但下载网页内容可能需要几秒钟。
至于下载文件,您可以使用HttpWebRequest
获取HttpWebResponse
,然后使用方法GetResponseStream()
获取数据流。
这会有所帮助: Encoding trouble with HttpWebResponse
尤其是byte[] buffer
用于获取部分数据而非StreamReader
ReadToEnd()
方法的部分。下载部分数据到缓冲区时,可以根据超时DateTime检查当前的DateTime,从而允许在它之后取消下载。
编辑一段有用的代码
private byte[] DownloadFile( string uri, int requestTimeout, int downloadTimeout, out bool isTimeout, out int bytesDownloaded )
{
HttpWebRequest request = WebRequest.Create( uri ) as HttpWebRequest;
request.Timeout = requestTimeout;
HttpWebResponse response = null;
Stream responseStream = null;
MemoryStream downloadedData = null;
byte[] result = null;
bytesDownloaded = 0;
isTimeout = false;
try
{
// Get response
response = request.GetResponse() as HttpWebResponse;
byte[] buffer = new byte[ 16384 ];
// Create buffer for downloaded data
downloadedData = new MemoryStream();
// Set the timeout
DateTime timeout = DateTime.Now.Add( new TimeSpan( 0, 0, 0, 0, downloadTimeout ) );
// Read parts of the stream
responseStream = response.GetResponseStream();
int bytesRead = 0;
DateTime now = DateTime.Now;
while ( (bytesRead = responseStream.Read( buffer, 0, buffer.Length )) > 0 && DateTime.Now < timeout )
{
downloadedData.Write( buffer, 0, bytesRead );
now = DateTime.Now;
bytesDownloaded += bytesRead;
}
// Notify if timeout occured (could've been written better)
if ( DateTime.Now >= timeout )
{
isTimeout = true;
}
}
catch ( WebException ex )
{
// Grab timeout exception
if ( ex.Status == WebExceptionStatus.Timeout )
{
isTimeout = true;
}
}
finally
{
// Close the stream
if ( responseStream != null )
{
responseStream.Close();
}
}
if ( downloadedData != null )
{
result = downloadedData.GetBuffer();
downloadedData.Close();
}
return result;
}
<强>用法强>
private void button1_Click( object sender, EventArgs e )
{
bool isTimeout;
int bytesDownloaded;
byte[] data = DownloadFile( something, 1000,500, out isTimeout, out bytesDownloaded );
MessageBox.Show( "Downloaded " + bytesDownloaded.ToString() + " bytes, Timeout = " + isTimeout.ToString() );
}
此代码仍然容易受到您可能遇到的其他异常的影响,请记住这一点。