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

本文关键字:文件 启动 速度 复制 何提高 | 更新日期: 2024-09-26 04:36:51

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

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秒甚至更长的

如何删除或减少此额外时间

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

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

操作系统假装你在7秒内复制了400 MiB,但你没有。您刚刚向操作系统(或文件系统)发送了400MiB,以便将来进行写入,这是缓冲区所能占用的最大容量。如果你试图写一个400 MiB的文件,并且在"完成"后立即拔掉插头,你的文件将不会被写入。同样的事情也涉及"超时"——你的应用程序已经把它所有的东西都发送到了缓冲区,但缓冲区还没有写入驱动器本身(要么是它的缓冲区,要么更慢,实际的物理磁盘)。

这一点在USB闪存驱动器中尤其明显,因为USB闪存驱动器往往大量使用缓存。这使得使用(通常非常慢)驱动器更加愉快,同时还需要等待操作系统完成所有内容的写入,然后才能取出驱动器(这就是为什么你会得到"安全删除"图标)。

因此,很明显,您无法真正缩短时间。你所能做的就是试着让用户界面更好地反映现实,这样用户就不会看到"前400架MiB太快了!"。。。但效果并不好。在任何情况下,您的读写速度都是~30 MiB/s。操作系统只是隐藏峰值,以便更容易处理速度较慢的硬盘驱动器——当你处理大量小文件时非常有用,而当处理比缓冲区大的文件时则毫无价值。

当您直接使用FileStream构造函数而不是使用File.OpenWrite时,您可以控制这一点——您可以使用FileOptions.WriteThrough指示操作系统避免任何缓存并直接写入磁盘[1],从而更好地了解实际写入速度。请注意,这通常会使时间变大,并且可能会使并发访问变得更糟。你绝对不想把它用于小文件。

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

您可以尝试增加缓冲区大小。当写缓存无法再跟上时(如其他答案中所讨论的),这一点非常重要。写很多小块通常比写几个大块慢。尝试1MB、4MB甚至更大的,而不是64kB

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