计算文件复制的剩余时间

Fre*_*red 6 c# math file-copying

我有一个应用程序,通过网络将大量文件复制到文件服务器(而不是Web).我试图显示剩余时间的一半估计.

我已经看了很多关于SO的文章,但问题得到了解决,我没有尝试过我真正想做的事情.我希望估计的剩余时间相对稳定IE不会在整个地方跳转,这取决于波动的传输速度.

所以我看到的第一个解决方案是计算传输速度,以每秒字节数为单位

double bytePerSec = totalBytesCopied / TimeTaken.TotalSeconds;
Run Code Online (Sandbox Code Playgroud)

然后将剩余的总字节除以传输速率.

double secRemain = (totalFileSizeToCopy - totalBytesCopied) / bytePerSec;
Run Code Online (Sandbox Code Playgroud)

我认为,一旦复制了几MB,剩余的时间会变得更加稳定(尽管期望它会改变.但事实并非如此,它的不稳定性和跳跃遍布整个地方.

然后我在SO上尝试了一个解决方案....

double secRemain = (TimeTaken.TotalSeconds / totalBytesCopied) * (totalFileSizeToCopy - totalBytesCopied);
Run Code Online (Sandbox Code Playgroud)

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

所以现在我有点想我需要从不同的角度来看待这个问题.IE使用平均值?使用某种倒数计时器并重置每隔一段时间的时间?只是寻找已经遇到过这个问题的人的意见或建议.

Ste*_*ens 5

这里是你将如何异步复制文件的工作示例D:\dummy.binD:\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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)