如何提高或保持复制文件的启动速度

时间:2016-04-18 10:59:12

标签: c# file-copying

我正在使用这些代码复制一个大文件:

const int CopyBufferSize = 64 * 1024;

string src = @"F:\Test\src\Setup.exe";
string dst = @"F:\Test\dst\Setup.exe";

public void CopyFile()
{
        Stream input = File.OpenRead(src);
        long length = input.Length;
        byte[] buffer = new byte[CopyBufferSize];
        Stopwatch swTotal = Stopwatch.StartNew();

        Invoke((MethodInvoker)delegate
        {
            progressBar1.Maximum = (int)Math.Abs(length / CopyBufferSize) + 1;
        });


        using (Stream output = File.OpenWrite(dst))
        {
            int bytesRead = 1;
            // This will finish silently if we couldn't read "length" bytes.
            // An alternative would be to throw an exception
            while (length > 0 && bytesRead > 0)
            {
                bytesRead = input.Read(buffer, 0, Math.Min(CopyBufferSize, buffer.Length));
                output.Write(buffer, 0, bytesRead);
                length -= bytesRead;

                Invoke((MethodInvoker)delegate
                {
                    progressBar1.Value++;
                    label1.Text = (100 * progressBar1.Value / progressBar1.Maximum).ToString() + " %";
                    label3.Text = ((int)swTotal.Elapsed.TotalSeconds).ToString() + " Seconds";
                });
            }

            Invoke((MethodInvoker)delegate
            {
                progressBar1.Value = progressBar1.Maximum;
            });
        }

        Invoke((MethodInvoker)delegate
        {
            swTotal.Stop();
            Console.WriteLine("Total time: {0:N4} seconds.", swTotal.Elapsed.TotalSeconds);
            label3.Text += ((int)swTotal.Elapsed.TotalSeconds - int.Parse(label3.Text.Replace(" Seconds",""))).ToString() + " Seconds";
        });
    }

文件大小约为4 GB。

  

在最初的7秒内,它可以复制到400 MB,然后这个热速度会降低。

发生了什么以及如何保持这种热速甚至增加它?

另一个问题是: 复制文件时,Windows仍然在目标文件上工作(大约10秒)。

  

复制时间:116秒

     

额外时间:10-15秒甚至更多

如何删除或减少这段额外时间?

2 个答案:

答案 0 :(得分:1)

会发生什么?主要是缓存。

操作系统假装你在七秒内复制了400 MiB,但你没有。您刚刚向OS(或文件系统)发送了400 MiB以便将来写入,这与缓冲区可以采用的一样多。如果您尝试编写400 MiB文件并在插件“完成”后立即拔出,则不会写入您的文件。同样的事情处理“加班” - 你的应用程序已将它已经发送到缓冲区,但缓冲区尚未写入驱动器本身(其缓冲区,甚至更慢,实际的物理盘片)。

这一点在USB闪存驱动器中尤为明显,后者往往会大量使用缓存。这使得(通常非常慢)驱动器的工作更加愉快,需要权衡,你必须等待操作系统完成所有内容的编写,然后才能将驱动器拉出(这就是为什么你得到“安全删除”图标)。

所以很明显,你不能真正缩短时间。你所能做的只是尝试让用户界面更好地反映现实,这样用户就不会看到“前400 MiB如此之快!”事情......但它并没有真正奏效。在任何情况下,您的读 - >写速度约为30 MiB / s。操作系统只是隐藏了峰值,以便更容易处理慢速硬盘 - 当你处理大量小文件时非常有用,在处理大于缓冲区的文件时毫无价值。

当您直接使用FileStream构造函数而不是使用File.OpenWrite时,您可以对此进行一些控制 - 您可以使用FileOptions.WriteThrough来指示操作系统避免任何缓存和写入直接到磁盘[1],让您更好地了解真正的写入速度。请注意,这通常会使时间变大,并且可能会使并发访问更加糟糕。你绝对不想将它用于小文件。

[1] - 哈哈,对。驱动器通常有自己的缓存,有些人忽略操作系统的请求。好运。

答案 1 :(得分:0)

您可以尝试的一件事是增加缓冲区大小。当写缓存无法跟上时,这非常重要(如其他答案中所述)。编写大量小块通常比写几块大块慢。而不是64 kB,尝试1 MB,4 MB甚至更大:

const int CopyBufferSize = 1 * 1024 * 1024;   // 1 MB
// or
const int CopyBufferSize = 4 * 1024 * 1024;   // 4 MB