Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ssl/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#与队列列表异步下载_C#_Downloadfile_Downloadfileasync - Fatal编程技术网

C#与队列列表异步下载

C#与队列列表异步下载,c#,downloadfile,downloadfileasync,C#,Downloadfile,Downloadfileasync,如果你不费心阅读全文,你可以跳到最后两个点:p 这个网站在过去已经帮了我十几次,但现在我真的需要帮助自己 问题如下: 首先,我使用了DownloadFile函数和showui选项。这很好,但是UI很难看,没有太多可用的选项 然后我切换到DownloadFileAsync和changed progress事件,以便基本上拥有自己的UI。我遇到的唯一问题是,我循环浏览程序必须下载的文件列表,并调用download函数(它调用DownloadAsync函数)。像这样: foreach (ListVi

如果你不费心阅读全文,你可以跳到最后两个点:p

这个网站在过去已经帮了我十几次,但现在我真的需要帮助自己

问题如下:

  • 首先,我使用了DownloadFile函数和showui选项。这很好,但是UI很难看,没有太多可用的选项

  • 然后我切换到DownloadFileAsync和changed progress事件,以便基本上拥有自己的UI。我遇到的唯一问题是,我循环浏览程序必须下载的文件列表,并调用download函数(它调用DownloadAsync函数)。像这样:

    foreach (ListViewItem t in themeList.CheckedItems)
            {
                DownloadFile(file to be downloaded);
            }
    
  • 但显然这不起作用,因为DownloadFileAsync函数不支持同时进行多个调用,因为没有像DownloadFile那样的队列系统,所以它只下载第一个被调用的文件。 因此,我所做的是创建一个函数,将要下载的文件添加到一个数组中,让backgroundworker在列表中循环,并等待调用DownloadAsync,直到上一次下载完成。这算是成功了。代码如下:

    #region "Download functions"
    //Function that converts download speed to a nice user friendly format
    private static string BpsToString(double bps)
    {
        var m = new string[] { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
        var i = 0;
        while (bps >= 0.9 * 1024)
        {
            bps /= 1024;
            i++;
        }
    
        return String.Format("{0:0.00} {1}/sec", bps, m[i]);
    }
    
    private bool _complete = false;
    private string _speed;
    private int _secondsRemaining = -1;
    private long _transferred = 0;
    private Stopwatch _sw = new Stopwatch();
    private List<string[]> _fd = new List<string[]>();
    private void DownloadFile(string url, string des, bool overwrite = false)
    {
        if (overwrite) //if the file needs to be overwritten or not
        {
            if (File.Exists(des)) File.Delete(des);
        }
        else
        {
            if (File.Exists(des)) return;
        }
    
        if (!Directory.Exists(Path.GetDirectoryName(des))) //create the directory if it doesn't exist
            Directory.CreateDirectory(Path.GetDirectoryName(des));
    
        string[] file = {url, des};
        _fd.Add(file); //add file to queue list
    
        if(!backgroundDownloader.IsBusy) //if downloader isn't doing anything, start it again
            backgroundDownloader.RunWorkerAsync();
    }
    
    //function called by the backgroundworker to actually download the file
    private void ContinueDownloadFile(string url, string des)
    {
        var webClient = new WebClient();
        webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
        webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged);
        webClient.DownloadFileAsync(new Uri(_fd[0][0]), _fd[0][1]);
    }
    
    //when download completed, set progress bar to 0% and remove the first (0) download from the queue
    private void Completed(object sender, AsyncCompletedEventArgs e)
    {
        SetProgressText("Idle");
        SetProgressValue(0);
    
        if(_fd.Count != 0)
            _fd.RemoveAt(0);
    
        _complete = true; //if it's complete, set to true so the backgroundworker knows it can start the next download
    }
    
    //progress bar value change and status change for download speed etc...
    private void ProgressChanged(object sender, DownloadProgressChangedEventArgs e)
    {
        if(progressLabel.Text == "Idle")
            SetProgressText("Downloading...");
    
        if (_sw.Elapsed >= TimeSpan.FromSeconds(1))
        {
            _sw.Stop();
    
            var bytes = e.BytesReceived - _transferred;
            var bps = bytes * 1000.0 / _sw.Elapsed.TotalMilliseconds;
            _speed = BpsToString(bps);
    
            _secondsRemaining = (int)((e.TotalBytesToReceive - e.BytesReceived) / bps);
    
            _transferred = e.BytesReceived;
            _sw.Reset();
            _sw.Start();
    
            SetProgressText("Downloading: " + e.ProgressPercentage + "% | Seconds remaining: " +
            _secondsRemaining + " | Files remaining: " + _fd.Count + " | Speed: " + _speed);
        }
    
        SetProgressValue(e.ProgressPercentage);
    }
    
    //the backgroundworker who starts the downloads from the list one by one
    private void BackgroundDownloaderDoWork(object sender, DoWorkEventArgs e)
    {
        while (_fd.Count != 0)
        {
            _sw.Start();
            _complete = false; //let the backgroundworker wait till the download is complete
            ContinueDownloadFile(_fd[0][0], _fd[0][1]);
    
            while(!_complete) //let it wait here
                Thread.Sleep(100);
    
            _sw.Stop();
            _sw.Reset();
        }
    }
    
    #endregion
    
  • 这显然不是最好的解决方案,因为他们可以在下载忙的时候点击其他东西,但是是的,线程。睡眠会冻结一切。 相反,我会制作一个等待表单(这里可能是一个进度条,而不是在主表单上),将注意力集中在主表单的顶部,这样他们就不能单击主表单并放置线程。在主表单上睡觉

  • 你将如何解决这个问题?您是否也会使用backgroundworker循环文件数组,或者是否有更简单、更有效的方法。可能不使用DownloadFileAsync,而是手动下载套接字

  • 我基本上希望同步下载文件,但有自己的UI(因此我需要使用异步下载功能)。哈哈


我希望我已经告诉你了。提前感谢。

使用一个模式对话框,可能会添加一个进度条以满足视觉需求,通知用户某个流程正在运行


通过这种方式,您可以在不允许与主窗体控件交互的情况下执行异步下载。

使用一个模式对话框,可能会添加一个进度条以满足视觉需求,通知用户某个过程正在工作


通过这种方式,您可以在不允许与主窗体控件交互的情况下执行异步下载。

也许这是一个“TL;DR”帖子?我会把它写得更简短一些,因为它确实包含一些不必要的内容您的bullet#5计划听起来是最好的方式。您还可以尝试使用任务并行库(TPL)。这将简化并发下载调用,并且您可以使用同步文件下载程序。也许这是一个“TL;DR”帖子?我会把它写得更简短,因为它确实包含一些不必要的内容。您的bullet#5计划听起来是最好的方式。您还可以尝试使用任务并行库(TPL)。它将简化并发下载调用,并且您可以使用同步文件下载程序。谢谢,我将查看模式对话框。我似乎无法关闭模式对话框以执行进一步的代码。我试着在等待窗体上设置一个计时器,当进度条达到100时,它会将DialogResult设置为OK,但它不会关闭。在主窗体的backgroundworker中尝试了它,但没有关闭。当你开始下载时,显示你的模态对话框。在异步回调中,您应该处理该对话框。谢谢。调用DownloadFileAsync后,显示对话框。它可以很好地下载第一个文件并关闭。然后,它再次打开对话框(第二个文件),但它就在那里(idle和progressbar值为0)。我执行_wait=new wait,然后在下载FileAsync后立即调用ShowDialog(this)。谢谢,我将查看模式对话框。我似乎无法关闭模式对话框以执行进一步的代码。我试着在等待窗体上设置一个计时器,当进度条达到100时,它会将DialogResult设置为OK,但它不会关闭。在主窗体的backgroundworker中尝试了它,但没有关闭。当你开始下载时,显示你的模态对话框。在异步回调中,您应该处理该对话框。谢谢。调用DownloadFileAsync后,显示对话框。它可以很好地下载第一个文件并关闭。然后,它再次打开对话框(第二个文件),但它就在那里(idle和progressbar值为0)。我做_wait=new wait,然后在下载FileAsync之后立即调用ShowDialog(this)。
while (_fd.Count != 0)
        Application.DoEvents();