【问题标题】:I cant update progress bar while downloading a file下载文件时无法更新进度条
【发布时间】:2014-10-14 05:45:31
【问题描述】:

我正在尝试制作一个简单的下载管理器。它可以工作。问题是如果我添加一个进度条来通知用户我会收到此异常

此流不支持查找操作

 while ((readed = ReadFrom.Read(read, 0, read.Length)) > 0)
            {

                strLocal.Write(read, 0, readed);
                **UpdateProgress(ReadFrom.Length, strLocal.Length);// throws exception**
            }

这是所有代码

  private void button1_Click(object sender, EventArgs e)
        {
            req = (HttpWebRequest)HttpWebRequest.Create(new Uri(url));
            res = (HttpWebResponse)req.GetResponse();
            Int64 contentlength = res.ContentLength;
            WebClient wc = new WebClient();
            Stream ReadFrom= wc.OpenRead(new Uri(url));

            strLocal = new FileStream(@"E:\\xxx.tar.gz", FileMode.Create, FileAccess.Write, FileShare.None);
            byte[]read=new byte[1024];

            int readed = 0;
            while ((readed = ReadFrom.Read(read, 0, read.Length)) > 0)
            {

                strLocal.Write(read, 0, readed);
                UpdateProgress(ReadFrom.Length, strLocal.Length);
            }

            strLocal.Close();
            ReadFrom.Close();

        }

        private void UpdateProgress(long Filesize, long readedBytes)
        {
          //  progressBar1.Maximum = 100;
         int downloaded =Convert.ToInt32((readedBytes * 100) / Filesize);
         progressBar1.Value = downloaded;
        }

这里有什么问题?

@编辑

        HttpWebRequest req;
        HttpWebResponse res;
        Stream strLocal;
        Stream ResponseStr;
        byte[] bytes = null;
        Thread thr;
        delegate void UpdateCallBack(long l1, long l2);
        public Form1()
        {
            InitializeComponent();
        }
        string url="https://www.unrealircd.org/downloads/Unreal3.2.10.3.tar.gz";
        ////string url2 = "http://www.microsoft.com/en-us/download/confirmation.aspx?id=34794&6B49FDFB-8E5B-4B07-BC31-15695C5A2143=1";
        string filename = @"C:\\Unreal3.2.10.3.tar.gz";
        private void Form1_Load(object sender, EventArgs e)
        {

        }



        private void button1_Click(object sender, EventArgs e)
        {
            thr = new Thread(download);
            thr.Start();

        }

private void download()
{
            req = (HttpWebRequest)HttpWebRequest.Create(new Uri(url));
            res = (HttpWebResponse)req.GetResponse();

            Int64 contentlength = res.ContentLength;

            ResponseStr = res.GetResponseStream();

            strLocal = new FileStream(@"E:\\xxx.tar.gz", FileMode.Create, FileAccess.Write, FileShare.None);
            byte[]read=new byte[1024];

            int readed = 0;
            while ((readed = ResponseStr.Read(read, 0, read.Length)) > 0)
            {

                strLocal.Write(read, 0, readed);
                this.Invoke(new UpdateCallBack(this.UpdateProgress), new object[] {ResponseStr.Length,strLocal.Length });


            }

            strLocal.Close();
            ResponseStr.Close();
}

        private void UpdateProgress(long Filesize, long readedBytes)
        {

         int updated =Convert.ToInt32((readedBytes * 100) / Filesize);
         progressBar1.Value = updated;
        }

@edit2

private void download()
{
            req = (HttpWebRequest)HttpWebRequest.Create(new Uri(url));
            res = (HttpWebResponse)req.GetResponse();

            Int64 contentlength = res.ContentLength;

            ResponseStr = res.GetResponseStream();


            strLocal = new FileStream(@"E:\\xxx.tar.gz", FileMode.Create, FileAccess.Write, FileShare.None);


            byte[]read=new byte[1024];

            int readed = 0;
            while ((readed = ResponseStr.Read(read, 0, read.Length)) > 0)
            {

                strLocal.Write(read, 0, readed);
                backgroundWorker1.RunWorkerAsync();
              //  this.Invoke(new UpdateCallBack(this.UpdateProgress), new object[] {ResponseStr.Length,strLocal.Length });


            }

            strLocal.Close();
            ResponseStr.Close();
}

        private void UpdateProgress(long Filesize, long readedBytes)
        {

         int updated =Convert.ToInt32((readedBytes * 100) / Filesize);
         progressBar1.Value = updated;
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar1.Value = e.ProgressPercentage;
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            UpdateProgress(ResponseStr.Length, strLocal.Length);
        }

【问题讨论】:

  • 我猜这里存在线程问题。您是否尝试过使用 BackgroundWorker 来代替
  • 您在 UI 线程上进行所有处理。所以进度条无法更新。
  • 有什么异常?你的progressBar1 的属性是什么(比如MaxValue)

标签: c#


【解决方案1】:

您的所有操作都发生在同一个线程上。在您进行下载时,应用程序会停止更新 UI。我通常使用 BackgroundWorker 来更新此类情况的进度条。

Here's an MSDN resource on background workers.

根据您的编辑,这里有一些代码:

// At the class level, put this:
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerReportsProgress = true; // This means we want to send updates from the background worker.

// The DoWork method handles your time consuming task, which in this case is your download method. So you can try this:
private void Download()
{
    bw.RunWorkerAsync();
}

// This should be called as a result:
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
    // The worker who's progress will be updated.
    BackgroundWorker worker = sender as BackgroundWorker;

    req = (HttpWebRequest)HttpWebRequest.Create(new Uri(url));
    res = (HttpWebResponse)req.GetResponse();

    Int64 contentLength = res.ContentLength;

    ResponseStr = res.GetResponseStream();

    strLocal = new FileStream(@"E:\xxx.tar.gz", FileMode.Create, FileAccess.Write, FileShare.None);

    byte[] read = new byte[1024];

    int readed = 0;
    while((readed = ResponseStr.Read(read, 0, read.Length)) > 0)
    {
        strLocal.Write(read, 0, readed);
        // Update the worker (this uses the number you calculated)
        worker.ReportProgress(Convert.ToInt32((ResponseStr.Length * 100) / strLocal.Length));

        strLocal.Close();
        ResponseStr.Close();
    }
}

// This is called via worker.ReportProgress
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    progressBar1.Value = e.ProgressPercentage;
}

你需要在你的类中定义后台工作者,并允许它接受进度更新。

那么,无论这个方法需要后台worker在哪里,你都需要调用RunWorkerAsync。您可以在下载方法中执行此操作,或者替换您调用下载的位置。

在你的 do 工作课上,你做你通常会做的所有事情,但是在你想要更新进度的情况下,你可以调用 ReportProgress 并提供必要的值。

如果您查看上面的链接,还有其他可以实现的方法 - 如果您担心取消后台工作人员或出现错误或其他任何问题。

编辑

如果您仍然收到错误,我刚刚意识到这可能是您试图从 Stream 对象中提取长度的事实。如果错误仍然存​​在,请查看this question

【讨论】:

  • 我已经按照你的建议使用线程更新了我的代码。但是问题仍然存在
  • 好的。我整天都在上课,今晚我会试着看看。如果您想要另一个参考here is a question I asked a while back that is really similar.
  • 非常感谢。我将继续尝试解决方案,因为。我在后台工作时也遇到了同样的异常。请参阅编辑 2
  • 好吧,我给你看了很多,但试一试。
  • @user3733078 运气好吗?
【解决方案2】:

如上所述,它与线程有关。因此,您需要在多个线程上分离操作才能更新您的 UI。你也可以使用 async 和 await 来解决这个问题。下面是一篇不错的文章,文章是关于执行一些操作和更新 UI。

http://www.i-programmer.info/programming/c/1514-async-await-and-the-ui-problem.html

【讨论】:

    猜你喜欢
    • 2020-12-18
    • 1970-01-01
    • 1970-01-01
    • 2011-10-27
    • 2015-11-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多