You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

获取文件大小异常时progressBarEx2显示NaN的问题排查

问题分析

  1. 无效文件大小导致总进度异常:GetFileSizeAsync返回-1时直接累加到totalBytesToReceive,导致总和为负数,后续设置progressBarEx2.Maximum为0时,进度计算出现除以0的情况,显示NaN。
  2. 总进度计算逻辑错误:原代码中overallProgress = e.BytesReceived + progressBarEx2.Maximum * currentDownloadIndex的逻辑完全错误,progressBarEx2.Maximum是总大小,乘以已完成文件数会导致数值远超实际进度。
  3. ProgressBar显示限制:WinForms的ProgressBar当Maximum和Minimum都为0时,无法正常计算进度百分比,会出现异常显示。

修复方案

1. 修正文件大小统计逻辑

  • 新增变量记录已完成文件的总大小、未知大小的文件数量,避免无效值干扰总进度计算。
  • 仅将有效文件大小(>0)计入总大小,未知大小的文件单独处理。

2. 调整总进度条的Maximum设置

  • 若存在有效总大小,设置为该值;若全为未知大小,将Maximum设置为文件总数,按完成文件数展示进度。

3. 修正总进度计算逻辑

  • 维护已完成文件的总大小,总进度为已完成大小加上当前文件已下载大小;若总大小未知,则按已完成文件数占总文件数的比例计算进度。

4. 处理下载完成后的真实大小更新

  • 在文件下载完成后,若之前获取的大小无效,用实际下载的文件大小更新总进度数据。

修改后的完整代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Download_Webclient
{
    public partial class Form1 : Form
    {
        private readonly Stopwatch stopwatch = new Stopwatch();
        private List<string> downloadLinks;
        private int currentDownloadIndex;
        private long totalValidBytes; // 仅统计有效文件大小(>0)
        private long completedTotalBytes; // 已完成文件的总大小
        private int unknownSizeFileCount; // 未知大小的文件数量

        public Form1()
        {
            InitializeComponent();

            downloadLinks = new List<string>
            {
                "https://hil-speed.hetzner.com/100MB.bin",
                "https://hil-speed.hetzner.com/100MB.bin",
                "https://hil-speed.hetzner.com/100MB.bin",
                "https://hil-speed.hetzner.com/100MB.bin",
                // 可添加更多链接
            };
        }

        private async void btnDownload_Click(object sender, EventArgs e)
        {         
            using (var folderDialog = new FolderBrowserDialog())
            {
                DialogResult result = folderDialog.ShowDialog();
                if (result == DialogResult.OK)
                {
                    btnDownload.Enabled = false;
                    progressBarEx1.Value = 0;
                    progressBarEx2.Value = 0;

                    totalValidBytes = 0;
                    unknownSizeFileCount = 0;
                    completedTotalBytes = 0;
                    currentDownloadIndex = 0;

                    // 预先统计有效文件大小和未知文件数
                    List<long> fileSizes = new List<long>();
                    foreach (string downloadLink in downloadLinks)
                    {
                        Uri uri = new Uri(downloadLink);
                        long size = await GetFileSizeAsync(uri);
                        fileSizes.Add(size);
                        if (size > 0)
                        {
                            totalValidBytes += size;
                        }
                        else
                        {
                            unknownSizeFileCount++;
                        }
                    }

                    // 设置总进度条的最大值
                    if (totalValidBytes > 0)
                    {
                        progressBarEx2.Maximum = (int)totalValidBytes;
                    }
                    else
                    {
                        // 全为未知大小,按文件数量设置进度
                        progressBarEx2.Maximum = downloadLinks.Count;
                        progressBarEx2.Minimum = 0;
                    }

                    // 开始逐个下载
                    for (int i = 0; i < downloadLinks.Count; i++)
                    {
                        string downloadLink = downloadLinks[i];
                        long fileSize = fileSizes[i];
                        Uri uri = new Uri(downloadLink);
                        string fileName = System.IO.Path.Combine(folderDialog.SelectedPath, System.IO.Path.GetFileName(uri.LocalPath));

                        using (WebClient wc = new WebClient())
                        {
                            // 捕获当前文件的大小,用于更新总进度
                            long currentFileSize = fileSize;
                            wc.DownloadProgressChanged += (s, eArgs) => OnDownloadProgressChange(s, eArgs, currentFileSize);
                            wc.DownloadFileCompleted += (s, eArgs) => OnDownloadFileComplete(s, eArgs, fileName, currentFileSize);

                            stopwatch.Start();
                            await wc.DownloadFileTaskAsync(uri, fileName);
                        }

                        currentDownloadIndex++;
                    }

                    lblProgress.Text = "所有下载完成!";
                    AdjustLabelPosition(lblProgress, progressBarEx1);
                    btnDownload.Enabled = true;
                }
            }
        }

        private async Task<long> GetFileSizeAsync(Uri uri)
        {
            try
            {
                using (HttpClient httpClient = new HttpClient())
                {
                    using (var response = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, uri)))
                    {
                        if (response.Headers.Contains("Content-Length") &&
                            long.TryParse(response.Headers.GetValues("Content-Length").FirstOrDefault(), out long contentLength))
                        {
                            return contentLength;
                        }
                    }
                }
            }
            catch (HttpRequestException ex)
            {
                Console.WriteLine($"获取文件大小出错: {ex.Message}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"发生意外错误: {ex.Message}");
            }
            return -1;
        }

        private void OnDownloadProgressChange(object sender, DownloadProgressChangedEventArgs e, long currentFileSize)
        {
            // 单个文件进度处理
            string downloadProgress = e.ProgressPercentage + "%";
            string downloadSpeed = string.Format("{0} MB/s", (e.BytesReceived / 1024.0 / 1024.0 / stopwatch.Elapsed.TotalSeconds).ToString("0.00"));
            string downloadedMBs = Math.Round(e.BytesReceived / 1024.0 / 1024.0) + " MB";
            string totalMBs = Math.Round(e.TotalBytesToReceive / 1024.0 / 1024.0) + " MB";
            string progress = $"{downloadedMBs}/{totalMBs} ({downloadProgress}) @ {downloadSpeed}";

            lblProgress.Text = progress;
            AdjustLabelPosition(lblProgress, progressBarEx1);
            progressBarEx1.Value = e.ProgressPercentage;

            // 总进度处理
            if (totalValidBytes > 0)
            {
                // 有已知总大小,计算已完成+当前下载的字节数
                long overallProgress = completedTotalBytes + e.BytesReceived;
                progressBarEx2.Value = (int)Math.Min(totalValidBytes, overallProgress);
            }
            else
            {
                // 无已知总大小,按已完成文件数+当前文件进度比例计算
                int fileProgress = currentDownloadIndex + (int)((double)e.BytesReceived / e.TotalBytesToReceive);
                progressBarEx2.Value = Math.Min(downloadLinks.Count, fileProgress);
            }
        }

        private void OnDownloadFileComplete(object sender, AsyncCompletedEventArgs e, string fileName, long originalFileSize)
        {
            if (e.Error != null)
            {
                lblProgress.Text = $"下载文件出错: {e.Error.Message}";
            }
            else
            {
                // 更新已完成文件的总大小,如果原大小无效,用实际文件大小
                if (originalFileSize > 0)
                {
                    completedTotalBytes += originalFileSize;
                }
                else
                {
                    completedTotalBytes += new System.IO.FileInfo(fileName).Length;
                }

                if (currentDownloadIndex < downloadLinks.Count - 1)
                {
                    lblProgress.Text = $"正在下载下一个文件... ({currentDownloadIndex + 2}/{downloadLinks.Count})";
                }
                else
                {
                    lblProgress.Text = "所有下载完成!";
                    // 最后确保总进度条拉满
                    progressBarEx2.Value = progressBarEx2.Maximum;
                }
            }

            AdjustLabelPosition(lblProgress, progressBarEx1);
            stopwatch.Reset();
        }

        private void AdjustLabelPosition(Label label, ProgressBar progressBar)
        {
            int newY = progressBar.Top - label.Height - 5;
            int newX = progressBar.Left + (progressBar.Width - label.Width) / 2;
            label.Location = new Point(newX, newY);
        }
    }
}

关键修改点说明

  • 文件大小统计:新增totalValidBytes、unknownSizeFileCount和completedTotalBytes变量,分别统计有效总大小、未知大小文件数和已完成文件总大小,避免无效值干扰。
  • 总进度条Maximum设置:分两种情况,有有效总大小时设为总字节数,无有效大小时设为文件总数,确保进度计算有意义。
  • 总进度计算:根据是否有已知总大小,分别用字节数或文件完成比例计算进度,避免除以0的情况。
  • 下载完成后更新:若文件大小预先获取失败,下载完成后用实际文件大小更新总进度数据,保证最终进度准确。

内容的提问来源于stack exchange,提问作者Shien

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 15:08:12