【问题标题】:How to programmatically download a large file in C#如何在 C# 中以编程方式下载大文件
【发布时间】:2010-02-15 23:10:39
【问题描述】:

我需要在处理之前以编程方式下载一个大文件。最好的方法是什么?由于文件很大,我想特定的时间等待,以便我可以强制退出。

我知道 WebClient.DownloadFile()。但是似乎没有办法指定等待多长时间才能强制退出。

try
{
    WebClient client = new WebClient();
    Uri uri = new Uri(inputFileUrl);
    client.DownloadFile(uri, outputFile);
}
catch (Exception ex)
{
    throw;
}

另一种方法是使用命令行实用程序 (wget) 下载文件并使用 ProcessStartInfo 触发命令并使用 Process' WaitForExit(int ms) 强制退出。

ProcessStartInfo startInfo = new ProcessStartInfo();
//set startInfo object

try
{
    using (Process exeProcess = Process.Start(startInfo))
    {
        //wait for time specified
        exeProcess.WaitForExit(1000 * 60 * 60);//wait till 1m

        //check if process has exited
        if (!exeProcess.HasExited)
        {
            //kill process and throw ex
            exeProcess.Kill();
            throw new ApplicationException("Downloading timed out");
        }
    }
}
catch (Exception ex)
{
    throw;
}

有没有更好的方法?请帮忙。谢谢。

【问题讨论】:

  • 我试过第一个,效果很好。

标签: c# webclient download large-files


【解决方案1】:

使用WebRequest 并获取response stream。然后从响应流中读取字节块,并将每个块写入目标文件。这样,如果下载时间过长,您可以控制何时停止,因为您可以控制块之间,并且您可以根据时钟决定下载是否超时:      

        DateTime startTime = DateTime.UtcNow;
        WebRequest request = WebRequest.Create("http://www.example.com/largefile");
        WebResponse response = request.GetResponse();
        using (Stream responseStream = response.GetResponseStream()) {
            using (Stream fileStream = File.OpenWrite(@"c:\temp\largefile")) { 
                byte[] buffer = new byte[4096];
                int bytesRead = responseStream.Read(buffer, 0, 4096);
                while (bytesRead > 0) {       
                    fileStream.Write(buffer, 0, bytesRead);
                    DateTime nowTime = DateTime.UtcNow;
                    if ((nowTime - startTime).TotalMinutes > 5) {
                        throw new ApplicationException(
                            "Download timed out");
                    }
                    bytesRead = responseStream.Read(buffer, 0, 4096);
                }
            }
        }

【讨论】:

  • @orip,怎么复杂?
  • @Juan,一方面它是同步的。这个例子的异步版本看起来会很不一样。但它也抛弃了用户友好的 WebClient 外观,它隐藏了 90% 的时间基本上不相关的流管理内容。
  • orip,您的代码要简单得多。使用 Remus 的代码的一个优点是我可以知道文件的下载量。
  • @hlpPy:如果您更喜欢 WebClient.DownloadFileAsync/CancelAsync,您可以使用 WebClient.DownloadProgressChanged 事件来了解进度。
【解决方案2】:

在 WebClient 类中使用DownloadFileAsync 怎么样。走这条路线很酷的一点是,如果时间太长,您可以通过调用CancelAsync 取消操作。基本上,调用此方法,如果经过了指定的时间,则调用 Cancel。

【讨论】:

  • 如果文件的一部分已下载,CancelAsync 是保留该部分还是删除它?
【解决方案3】:

在这里提问:C#: Downloading a URL with timeout

最简单的解决方案:

public string GetRequest(Uri uri, int timeoutMilliseconds)
{
    var request = System.Net.WebRequest.Create(uri);
    request.Timeout = timeoutMilliseconds;
    using (var response = request.GetResponse())
    using (var stream = response.GetResponseStream())
    using (var reader = new System.IO.StreamReader(stream))
    {
        return reader.ReadToEnd();
    }
}

更好(更灵活)的解决方案是this answerWebClientWithTimeout 辅助类的形式解决同一问题。

【讨论】:

  • webrequest.timeout 只测量收到 HTTP 响应标头的时间,而不是下载响应正文的总时间。 IE。它会影响 GetResponse 返回之前的时间。
【解决方案4】:

您可以像@BFree 所说的那样使用DownloadFileAsync,然后尝试使用以下WebClient 的事件

protected virtual void OnDownloadProgressChanged(DownloadProgressChangedEventArgs e);
protected virtual void OnDownloadFileCompleted(AsyncCompletedEventArgs e);

那么你就可以知道进度百分比了

e.ProgressPercentage

希望对你有帮助

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-10
    • 1970-01-01
    • 2010-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-05
    • 1970-01-01
    相关资源
    最近更新 更多