我的问题是关于文件复制性能。我们有一个媒体管理系统,需要将文件系统上的大量文件移动到不同位置,包括同一网络上的 Windows 共享、FTP 站点、AmazonS3 等。当我们都在一个 Windows 网络上时,我们可以使用System.IO.File.Copy(source, destination) 复制文件。由于很多时候我们只有一个输入流(如 MemoryStream),我们尝试抽象 Copy 操作以获取输入流和输出流,但我们看到性能大幅下降。下面是一些用于复制文件以用作讨论点的代码。
public void Copy(System.IO.Stream inStream, string outputFilePath)
{
int bufferSize = 1024 * 64;
using (FileStream fileStream = new FileStream(outputFilePath, FileMode.OpenOrCreate, FileAccess.Write))
{
int bytesRead = -1;
byte[] bytes = new byte[bufferSize];
while ((bytesRead = inStream.Read(bytes, 0, bufferSize)) > 0)
{
fileStream.Write(bytes, 0, bytesRead);
fileStream.Flush();
}
}
}
有谁知道为什么它的执行速度比 File.Copy 慢得多?我可以做些什么来提高性能吗?我是否只需要放入特殊逻辑以查看我是否正在从一个窗口位置复制到另一个位置——在这种情况下我将只使用 File.Copy 而在其他情况下我将使用流?
请让我知道您的想法以及您是否需要更多信息。我尝试了不同的缓冲区大小,看起来 64k 的缓冲区大小对于我们的“小”文件来说是最佳的,而 256k+ 是我们的“大”文件的更好的缓冲区大小——但在任何一种情况下,它的性能都比 File.Copy( ).提前致谢!
最佳答案
File.Copy 是围绕 CopyFile 构建的Win32 函数和此函数引起了 MS 工作人员的大量关注(记住这个与 Vista 相关的关于复制性能缓慢的线程)。
提高方法性能的几条线索:
- 正如之前许多人所说,从您的循环中删除 Flush 方法。你根本不需要它。
- 增加缓冲区可能会有所帮助,但仅在文件到文件操作、网络共享或 ftp 服务器上这会减慢速度。 60 * 1024 是网络共享的理想选择,至少在 vista 之前是这样。对于 ftp,大多数情况下 32k 就足够了。
- 通过提供您的缓存策略(在您的情况下是顺序读取和写入)来帮助操作系统,使用 FileStream 构造函数覆盖 FileOptions参数(SequentalScan)。
- 您可以使用异步模式加快复制速度(特别适用于网络到文件的情况),但不要为此使用线程,而是使用重叠的 io(.net 中的 BeginRead、EndRead、BeginWrite、EndWrite),以及不要忘记在 FileStream 构造函数中设置异步选项(参见 FileOptions)
异步复制模式示例:
int Readed = 0;
IAsyncResult ReadResult;
IAsyncResult WriteResult;
ReadResult = sourceStream.BeginRead(ActiveBuffer, 0, ActiveBuffer.Length, null, null);
do
{
Readed = sourceStream.EndRead(ReadResult);
WriteResult = destStream.BeginWrite(ActiveBuffer, 0, Readed, null, null);
WriteBuffer = ActiveBuffer;
if (Readed > 0)
{
ReadResult = sourceStream.BeginRead(BackBuffer, 0, BackBuffer.Length, null, null);
BackBuffer = Interlocked.Exchange(ref ActiveBuffer, BackBuffer);
}
destStream.EndWrite(WriteResult);
}
while (Readed > 0);
关于c# - File.Copy 与手动 FileStream.Write 用于复制文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1246899/