我正在使用这些代码复制一个大文件:
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秒甚至更多
如何删除或减少这段额外时间?
答案 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