如何计算和显示每个文件的下载速度?

时间:2017-03-10 17:53:45

标签: c# .net winforms

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:\Temp\tempframes\" + fname + ".gif");

    lastDownloadedFile = @"C:\Temp\tempframes\" + 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:\Temp\tempframes\" + 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事件中显示下载速度。但我不确定如何使用这种方法。

不确定如何在progresschanged事件中使用它。

1 个答案:

答案 0 :(得分:1)

对您准备好的方法<xpath expr="//table[contains(@class, 'table-condensed')]/tr[first()]/td[first()]" position="replace"> <!-- YOUR XML HERE --> </xpath> 的调用最适合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

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

//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();
}

如果你需要一些更大的文件来测试它,我发现了一些here