2014-02-19 88 views
5

我有一个应用程序可以将大量文件通过网络复制到文件服务器(而不是网络)。我试图展示剩余时间的一半体面估计。计算文件复制上的剩余时间

我看过很多关于这个问题的文章,而这个问题已经解决了,我尝试过的没有一个真正做我想做的。我希望估计的时间仍然相对稳定I.E.根据波动的传输速度,不要在整个地方跳来跳去。

所以我看着所述第一解决方案是计算每秒

double bytePerSec = totalBytesCopied/TimeTaken.TotalSeconds; 

以字节为单位的传输速度,然后除以该传输速率的剩余的总字节。

​​

我估计剩余时间会变得更加稳定,一旦几MB已被复制(但期望它会改变。它没有,它的不稳定和跳跃周围所有的地方。

然后,我所以现在尝试了这样的解决方案之一....

double secRemain = (TimeTaken.TotalSeconds/totalBytesCopied) * (totalFileSizeToCopy - totalBytesCopied); 

这是一个类似的计算,但希望它可能会有所作为!

我是那种薄薄国王我需要从另一个角度来看待这个问题。 IE使用平均值?使用某种倒数计时器并重新设置每隔一段时间?只是寻找意见或最好从任何人已经有这个问题的建议。

+1

您可能还想考虑每个文件可能带有每文件滞后时间 - 用于打开流并在某处创建新文件。复制一百万个1kB文件需要更长的时间,而不是复制一个1 GB文件? –

+0

您可以使用“复制XXX中的1”来显示进度条吗? –

+0

[链接](http://stackoverflow.com/questions/2779600/how-to-estimate-download-time-remaining-accurately)这是你可能想要的。 – stepandohnal

回答

5

下面是一个工作示例,说明如何将文件D:\dummy.bin异步复制到D:\dummy.bin.copy,并使用计时器以秒为单位快照传输速率。

从这些数据中,我只需从最多30张快照(最新的第一张)中获取平均传输速率。从中我可以计算出转移文件其余部分需要多长时间的粗略估计。

此示例按原样提供,不支持在1次操作中复制多个文件。但它应该给你一些想法。

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Threading; 

public class Program 
{ 
    public static void Main(string[] args) 
    { 
     var sourcePath = @"D:\dummy.bin"; 
     var destinationPath = @"D:\dummy.bin.copy"; 
     var sourceFile = new FileInfo(sourcePath); 
     var fileSize = sourceFile.Length; 
     var currentBytesTransferred = 0L; 
     var totalBytesTransferred = 0L; 
     var snapshots = new Queue<long>(30); 
     var timer = new System.Timers.Timer(1000D); 
     timer.Elapsed += (sender, e) => 
     { 
      // 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 = fileSize - totalBytesTransferred; 
      Console.WriteLine("Average speed: {0:#} MBytes/second", averageSpeed/(1024 * 1024)); 
      if (averageSpeed > 0) 
      { 
       var timeLeft = TimeSpan.FromSeconds(bytesLeft/averageSpeed); 
       var timeLeftRounded = TimeSpan.FromSeconds(Math.Round(timeLeft.TotalSeconds)); 
       Console.WriteLine("Time left: {0}", timeLeftRounded); 
      } 
      else 
      { 
       Console.WriteLine("Time left: Infinite"); 
      } 
     }; 

     using (var inputStream = sourceFile.OpenRead()) 
     using (var outputStream = File.OpenWrite(destinationPath)) 
     { 
      timer.Start(); 
      var buffer = new byte[4096]; 
      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 => 
        { 
         outputStream.EndWrite(asyncWriteResult); 
         currentBytesTransferred = Interlocked.Add(ref currentBytesTransferred, numBytes); 
         totalBytesTransferred = Interlocked.Add(ref totalBytesTransferred, numBytes); 
         mre.Set(); 
        }, null); 
       }, null); 
       mre.WaitOne(timeout); 
      } while (numBytes != 0); 
      timer.Stop(); 
     } 
    } 
} 
1

您可能想要根据平均传输速率计算估计值。这应该有助于稳定估计。有another SO question问同样的问题。

1

这可能是一个形式给出

计算字节/秒时,第一文件的25%已被复制

使用该计算来估计的第一文件操作

的75%,其余

每次复制文件时,都会在集合中存储每个复制文件的速度的平均值(以字节/秒为单位)。

然后,您可以使用集合中项目的平均值来估计尚未复制的文件的复制操作时间。

让我知道如果你需要更多的细节或aproaches

1

你要根据平均传输速率来计​​算速度,但你希望它是一个移动平均线,因为网络速度过的的寿命变文件传输(特别是对于非常大的文件)。下面是我提出的JavaScript方法,似乎工作得很好(应该很容易转换为C#)。

var rates = []; 
var ratesLength = 1000; 
for (var i = 0; i < ratesLength; i++) 
    rates[i] = 0; 

/** 
* Estimates the remaining download time of the file. 
* 
* @param {number} bytesTransferred: Number of bytes transferred so far. 
* @param {number} totalBytes: Total number of bytes to be transferred. 
* @return {string} Returns the estimating time remaining in the upload/download. 
*/ 
function getSpeed(bytesTransferred, totalBytes) { 

    var bytes = bytesTransferred - oldBytesTransfered; 
    var time = currentTime - oldTime; 

    if ((time != 0) && (bytes != 0)) { 
     rates[rateIndex] = (bytes)/(time); 
     rateIndex = (rateIndex + 1) % rates.length; 
     var avgSpeed = 0; 
     var count = 0; 
     for (i = 0; i < rates.length ; i++) { 
      if (rates[i] != 0) { 
       avgSpeed += rates[i]; 
       count++; 
      } 
     } 
     if (count == 0) 
      return " "; 

     avgSpeed /= count; 
     return (humanReadableTime((totalBytes - bytesTransferred)/avgSpeed) + " remaining"); 
    } else { 
     return " "; 
    } 
} 

您可以调整ratesLength以获得所需的平滑度。 oldTime是收到最后一个字节的时间,oldBytesTransfered是最后一个字节后传输的字节总数。 bytesTransferred是包括当前卡盘在内的总转移量。

我发现这样做的加权平均值具有很好的准确性,但对速度的变化也有很好的反应。