我如何计算每个文件的下载速度


private void DownloadFile() {
  if (_downloadUrls.Any()) {
    WebClient client = new WebClient();
    client.DownloadProgressChanged += client_DownloadProgressChanged;
    client.DownloadFileCompleted += client_DownloadFileCompleted;
    var url = _downloadUrls.Dequeue();
    string startTag = "animated/";
    string endTag = "/infra";
    int index = url.IndexOf(startTag);
    int index1 = url.IndexOf(endTag);
    string fname = url.Substring(index + 9, index1 - index - 9);
    client.DownloadFileAsync(new Uri(url), @"C:Temptempframes" + fname + ".gif");
    lastDownloadedFile = @"C:Temptempframes" + fname + ".gif";
    label1.Text = url;
    return;
  }
  // End of the download
  btnStart.Text = "Download Complete";
}
private void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e) {
  if (e.Error != null) {
    // handle error scenario
    throw e.Error;
  }
  if (e.Cancelled) {
    // handle cancelled scenario
  }
  Image img = new Bitmap(lastDownloadedFile);
  Image[] frames = GetFramesFromAnimatedGIF(img);
  foreach(Image image in frames) {
    countFrames++;
    image.Save(@"C:Temptempframes" + countFrames + ".gif");
  }
  DownloadFile();
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) {
  double bytesIn = double.Parse(e.BytesReceived.ToString());
  double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
  double percentage = bytesIn / totalBytes * 100;
  pBarFileProgress.Value = int.Parse(Math.Truncate(percentage).ToString());
  label1.Text = e.BytesReceived.ToString() + "/" + e.TotalBytesToReceive.ToString();
}

现在我添加了此方法

DateTime lastUpdate;
long lastBytes = 0;
private void progressChanged(long bytes) {
  if (lastBytes == 0) {
    lastUpdate = DateTime.Now;
    lastBytes = bytes;
    return;
  }
  var now = DateTime.Now;
  var timeSpan = now - lastUpdate;
  var bytesChange = bytes - lastBytes;
  var bytesPerSecond = bytesChange / timeSpan.Seconds;
  lastBytes = bytes;
  lastUpdate = now;
}

我想使用此方法或另一种方法在Label2上的"进度变化事件"中显示下载速度。但是我不确定如何使用此方法。

不确定如何在"进度变化事件"中使用它。

对您准备的方法progressChanged的调用最适合client_DownloadProgressChanged

progressChanged(e.BytesReceived);

但是,您必须使用TotalSeconds代替Seconds,否则值不正确,并且还会导致零异常的划分

var bytesPerSecond = bytesChange / timeSpan.TotalSeconds;

这个辅助课程将跟踪收到的块,时间戳和进度:

public class DownloadProgressTracker
{
    private long _totalFileSize;
    private readonly int _sampleSize;
    private readonly TimeSpan _valueDelay;
    private DateTime _lastUpdateCalculated;
    private long _previousProgress;
    private double _cachedSpeed;
    private Queue<Tuple<DateTime, long>> _changes = new Queue<Tuple<DateTime, long>>();
    public DownloadProgressTracker(int sampleSize, TimeSpan valueDelay)
    {
        _lastUpdateCalculated = DateTime.Now;
        _sampleSize = sampleSize;
        _valueDelay = valueDelay;
    }
    public void NewFile()
    {
        _previousProgress = 0;
    }
    public void SetProgress(long bytesReceived, long totalBytesToReceive)
    {
        _totalFileSize = totalBytesToReceive;
        long diff = bytesReceived - _previousProgress;
        if (diff <= 0)
            return;
        _previousProgress = bytesReceived;
        _changes.Enqueue(new Tuple<DateTime, long>(DateTime.Now, diff));
        while (_changes.Count > _sampleSize)
            _changes.Dequeue();
    }
    public double GetProgress()
    {
        return _previousProgress / (double) _totalFileSize;
    }
    public string GetProgressString()
    {
        return String.Format("{0:P0}", GetProgress());
    }
    public string GetBytesPerSecondString()
    {
        double speed = GetBytesPerSecond();
        var prefix = new[] { "", "K", "M", "G"};
        int index = 0;
        while (speed > 1024 && index < prefix.Length - 1)
        {
            speed /= 1024;
            index++;
        }
        int intLen = ((int) speed).ToString().Length;
        int decimals = 3 - intLen;
        if (decimals < 0)
            decimals = 0;
        string format = String.Format("{{0:F{0}}}", decimals) + "{1}B/s";
        return String.Format(format, speed, prefix[index]);
    }
    public double GetBytesPerSecond()
    {
        if (DateTime.Now >= _lastUpdateCalculated + _valueDelay)
        {
            _lastUpdateCalculated = DateTime.Now;
            _cachedSpeed = GetRateInternal();
        }
        return _cachedSpeed;
    }
    private double GetRateInternal()
    {
        if (_changes.Count == 0)
            return 0;
        TimeSpan timespan = _changes.Last().Item1 - _changes.First().Item1;
        long bytes = _changes.Sum(t => t.Item2);
        double rate = bytes / timespan.TotalSeconds;
        if (double.IsInfinity(rate) || double.IsNaN(rate))
            return 0;
        return rate;
    }
}

在下面的示例中,进度跟踪器将为您提供最后一个50接收到的数据包的平均下载率,但只有每个500 ms(因此UI不会闪烁)。您可能需要稍微修补值,以在准确性和光滑之间找到良好的平衡。

//Somewhere in your constructor / initializer:
tracker = new DownloadProgressTracker(50, TimeSpan.FromMilliseconds(500));
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
    tracker.SetProgress(e.BytesReceived, e.TotalBytesToReceive);
    pBarFileProgress.Value = tracker.GetProgress() * 100;
    label1.Text = e.BytesReceived + "/" + e.TotalBytesToReceive;
    label2.Text = tracker.GetBytesPerSecondString();
}

请记住,您必须在每个新文件之前或之后重置跟踪器:

tracker.NewFile();

如果您需要一些更大的文件来对此进行测试,我在这里找到了一些

最新更新