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

C#计算下载进度百分比时在33%左右突然变为负数如何解决?

问题根源

你遇到的进度负数是32位有符号整数溢出导致的:

  • C#中int是32位有符号整数,最大值为2^31 - 1 = 2147483647
  • 计算100 * totalBytesCopied时,两个操作数都是int类型,会先按int规则计算再转double:当totalBytesCopied超过21474836时,100 * totalBytesCopied就会超过int最大值,溢出后值变为负数,最终计算出的进度自然为负。
  • 同时你的代码还存在一个潜在的文件损坏bug:WriteAsync传入的是buffer.Length而非实际读取到的bytesRead,如果最后一次读取未填满缓冲区,会将缓冲区多余的无效数据写入目标文件,导致下载的视频损坏。
修复方案
  1. 最优方案:将所有计数相关的变量改为long类型,从根本上避免溢出(支持最大2^63-1字节的文件,完全满足视频下载需求):
private async Task CopyStream(
      Lecture lecture,
      Stream source,
      Stream destination,
      long sourceLength, // int改long
      CancellationToken token,
      int bufferSize = (16 * 1024))
    {
      var buffer = new byte[bufferSize];

      if (sourceLength <= 0) return;

      long totalBytesCopied = 0; // int改long
      int bytesRead = -1;

      while (bytesRead != 0)
      {
        bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, token);

        if (bytesRead == 0) break;

        await destination.WriteAsync(buffer, 0, bytesRead, token); // buffer.Length改bytesRead

        totalBytesCopied += bytesRead;

        var progress = (int)Math.Round((double)(100 * totalBytesCopied) / sourceLength);

        Debug.WriteLine(
          $"Lecture={lecture.Title}, " +
          $"sourceLength={sourceLength}, " +
          $"totalBytesCopied={totalBytesCopied}, " +
          $"bytesRead={bytesRead}, progress={progress}");

        RaiseLectureDownloadProgressChangedEvent(null,
            new LectureDownloadProgressChangedEventArgs(lecture, progress));
      }
    }
  1. 临时兼容方案:如果不想修改入参类型,可以调整计算顺序,先转浮点型再做乘法,避免整数溢出:
var progress = (int)Math.Round(100 * (double)totalBytesCopied / sourceLength);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 03:45:03