2014-02-19 125 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是包括當前卡盤在內的總轉移量。

我發現這樣做的加權平均值具有很好的準確性,但對速度的變化也有很好的反應。