2

我想在复制大量文件(也是大文件)时获得准确的传输速率和剩余时间。这应该通过主进度条和定义的速度和剩余时间标签来可视化。

在例程开始时,后台工作人员遍历给定目录并构建具有源和目标路径的字典。

在此处找到的机制:计算文件复制的剩余时间。(史蒂文·利肯斯的回答)

问题是,永远不会达到 100% 的进度,它在某个时候以 96%-98% 完成,但从未达到 100%。使用不同的方法计算(递归)目录计算的总字节数可能有所不同。

下一点是,显示的传输速率甚至是正确的,如果它乘以 10 .... 所以我的 ssd 机器显示的传输速率显示为 30 MB/s,更像是 300 MB/s。显示的速率肯定是错误的。

所以这里有2个问题:1.)错误的进度计算2.)错误的传输率计算(速度还可以)

谁能指出为什么?

private void CopyFileList(DoWorkEventArgs eWorker)
    {
        if (fileWorker.CancellationPending)
        {
            eWorker.Cancel = true;
        }
        else
        {
            var totalBytes = GetTotalBytes();
            var currentBytesTransferred = 0L;
            var totalBytesTransferred = 0L;
            var snapshots = new Queue<long>(30);
            var timer = new System.Timers.Timer(100D);
            foreach (var file in FilesToCopy)
            {
                var sourcePath = file.Key;
                var destinationPath = file.Value;
                var sourceFile = new FileInfo(sourcePath);
                //var fileSize = sourceFile.Length;

                timer.Elapsed += (sender, e) =>
                {
                    if (fileWorker.CancellationPending)
                    {
                        eWorker.Cancel = true;
                    }
                    else
                    {
                        // Remember only the last 30 snapshots; discard older snapshots
                        if (snapshots.Count == 30)
                        {
                            snapshots.Dequeue();
                        }
                        snapshots.Enqueue(Interlocked.Exchange(ref currentBytesTransferred, 0L));
                        var averageSpeed = snapshots.Average();
                        var bytesLeft = totalBytes - totalBytesTransferred;
                        var speedText = string.Format("{0:#} MB/s", averageSpeed / (1024 * 1024));
                        var timeLeftText = string.Empty;
                        if (averageSpeed > 0)
                        {
                            var timeLeft = TimeSpan.FromSeconds(bytesLeft / averageSpeed);
                            var timeLeftRounded = TimeSpan.FromSeconds(Math.Round(timeLeft.TotalSeconds));
                            timeLeftText = string.Format("{0}", timeLeftRounded);
                        }
                        else
                        {
                            timeLeftText = ("-infinite-");
                        }
                        Console.WriteLine(speedText);
                        Console.WriteLine("Time Left: " + timeLeftText);

                        fileWorker.ReportProgress((currentBytesTransferred / maximum) * 100));
                    }
                };

                using (var inputStream = sourceFile.OpenRead())
                using (var outputStream = File.OpenWrite(destinationPath))
                {
                    timer.Start();
                    var buffer = new byte[4096 * 8];
                    var numBytes = default(int);
                    var numBytesMax = buffer.Length;
                    var timeout = TimeSpan.FromMinutes(10D);
                    do
                    {
                        var mre = new ManualResetEvent(false);
                        inputStream.BeginRead(buffer, 0, numBytesMax, asyncReadResult =>
                        {
                            numBytes = inputStream.EndRead(asyncReadResult);
                            outputStream.BeginWrite(buffer, 0, numBytes, asyncWriteResult =>
                            {
                                if (fileWorker.CancellationPending)
                                {
                                    eWorker.Cancel = true;
                                    return;
                                }
                                else
                                {
                                    outputStream.EndWrite(asyncWriteResult);
                                    currentBytesTransferred = Interlocked.Add(ref currentBytesTransferred, numBytes);
                                    Results.SizeProgressed = totalBytesTransferred;
                                    totalBytesTransferred = Interlocked.Add(ref totalBytesTransferred, numBytes);
                                    mre.Set();
                                }
                            }, null);
                        }, null);
                        mre.WaitOne(timeout);
                    } while (numBytes != 0);
                    timer.Stop();
                }
            }
        }
    }

一个例子:

将目录(21 个目录,228 个文件,总计:326MB)复制到 NAS 需要:12.4434796 秒,据报道平均速度为 2-3 MB/秒。但复制速度快了近10倍。

4

1 回答 1

0

我遇到了像你这样的问题。我检查了您的两个问题并相应地更改了代码。我稍微修改了您的代码以计算剩余时间和 MB/s 速度。

private void CopyFileList(DoWorkEventArgs eWorker)
{
   if (fileWorker.CancellationPending)
   {
      eWorker.Cancel = true;
   }
   else
   {
       var totalBytesTransferredInSecond = 0L;
       var totalBytes = GetTotalBytes();
       var currentBytesTransferred = 0L;
       var totalBytesTransferred = 0L;
       var timer = new System.Timers.Timer(1000D);
       foreach (var file in FilesToCopy)
       {
          var sourcePath = file.Key;
          var destinationPath = file.Value;
          var sourceFile = new FileInfo(sourcePath);
          //var fileSize = sourceFile.Length;

          timer.Elapsed += (sender, e) =>
          {
            if (fileWorker.CancellationPending)
            {
               eWorker.Cancel = true;
            }
            else
            {
                // Remember only the last 30 snapshots; discard older snapshots
                var bytesLeft = totalBytes - totalBytesTransferred;
                var speedText = string.Format("{0:#} MB/s", totalBytesTransferredInSecond / (1024 * 1024));
               var timeLeftText = string.Empty;
               if (totalBytesTransferredInSecond > 0)
               {
                  var timeLeft = TimeSpan.FromSeconds(bytesLeft / totalBytesTransferredInSecond);
                  var timeLeftRounded = TimeSpan.FromSeconds(Math.Round(timeLeft.TotalSeconds));
                  timeLeftText = string.Format("{0}", timeLeftRounded);
               }
               else
               {
                   timeLeftText = ("-infinite-");
               }
               Console.WriteLine(speedText);
               Console.WriteLine("Time Left: " + timeLeftText);
               totalBytesTransferredInSecond = 0;
           }
       };

       using (var inputStream = sourceFile.OpenRead())
       using (var outputStream = File.OpenWrite(destinationPath))
       {
          timer.Start();
          var buffer = new byte[1024 * 1024];
          var numBytes = default(int);
          var numBytesMax = buffer.Length;
          var timeout = TimeSpan.FromMinutes(10D);
          do
          {
               var mre = new ManualResetEvent(false);
               inputStream.BeginRead(buffer, 0, numBytesMax, asyncReadResult =>
               {
                  numBytes = inputStream.EndRead(asyncReadResult);
                  outputStream.BeginWrite(buffer, 0, numBytes, asyncWriteResult =>
                  {
                      if (fileWorker.CancellationPending)
                      {
                         eWorker.Cancel = true;
                         return;
                      }
                      else
                      {
                         outputStream.EndWrite(asyncWriteResult);
                         currentBytesTransferred = Interlocked.Add(ref currentBytesTransferred, numBytes);
                         totalBytesTransferredInSecond += currentBytesTransferred;
                         Results.SizeProgressed = totalBytesTransferred;
                         totalBytesTransferred = Interlocked.Add(ref totalBytesTransferred, numBytes);
                         mre.Set();
                         fileWorker.ReportProgress((currentBytesTransferred / maximum) * 100));
                      }
                 }, null);
              }, null);
             mre.WaitOne(timeout);
           } while (numBytes != 0);
           timer.Stop();
        }
     }
  }
}

请注意,我将计时器设置为 1000 毫秒。如果要将计时器设置为 100 毫秒,则必须将平均速度乘以 10。

totalBytesTransferredInSecond = totalBytesTransferredInSecond * 10;
var speedText = string.Format("{0:#} MB/s", totalBytesTransferredInSecond / (1024 * 1024));
于 2021-01-31T09:14:58.230 回答