我正在开发一个项目,需要复制许多文件和目录,同时保留它们的原始时间戳。因此,我需要多次调用目标的
由于这极大地限制了我的整个应用程序的性能,我想加快速度。我猜测,每个调用都需要打开和关闭与文件/目录的新流。如果是这个原因,我想在写完所有属性之前保持这个流打开。我该怎么做?我猜这需要使用一些 P/Invoke。
更新:
我遵循 Lukas 的建议,使用 WinAPI 方法
我使用的枚举类型可以在这里找到。这样只需要打开文件一次就能完成所有操作:创建文件、应用所有属性、设置时间戳并从原始文件复制实际内容。
SetCreationTime()
、SetLastWriteTime()
和SetLastAccessTime()
方法,以便将源中的原始值复制到目标中。如下面的屏幕截图所示,这些简单操作占用了总计算时间的 42%。
![performance analysis](https://istack.dev59.com/yUx89.webp)
更新:
我遵循 Lukas 的建议,使用 WinAPI 方法
CreateFile(..)
和 FILE_WRITE_ATTRIBUTES
。为了 P/Invoke 上述方法,我创建了以下包装器:public class Win32ApiWrapper
{
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern SafeFileHandle CreateFile(string lpFileName,
[MarshalAs(UnmanagedType.U4)] FileAccess dwDesiredAccess,
[MarshalAs(UnmanagedType.U4)] FileShare dwShareMode,
IntPtr lpSecurityAttributes,
[MarshalAs(UnmanagedType.U4)] FileMode dwCreationDisposition,
[MarshalAs(UnmanagedType.U4)] FileAttributes dwFlagsAndAttributes,
IntPtr hTemplateFile);
public static SafeFileHandle CreateFileGetHandle(string path, int fileAttributes)
{
return CreateFile(path,
(FileAccess)(EFileAccess.FILE_WRITE_ATTRIBUTES | EFileAccess.FILE_WRITE_DATA),
0,
IntPtr.Zero,
FileMode.Create,
(FileAttributes)fileAttributes,
IntPtr.Zero);
}
}
我使用的枚举类型可以在这里找到。这样只需要打开文件一次就能完成所有操作:创建文件、应用所有属性、设置时间戳并从原始文件复制实际内容。
FileInfo targetFile;
int fileAttributes;
IDictionary<string, long> timeStamps;
using (var hFile = Win32ApiWrapper.CreateFileGetHandle(targetFile.FullName, attributeFlags))
using (var targetStream = new FileStream(hFile, FileAccess.Write))
{
// copy file
Win32ApiWrapper.SetFileTime(hFile, timeStamps);
}
这样的努力是否值得?是的。优化后的运算时间从86秒缩短至51秒,约减少了40%。
优化前的结果:
优化后的结果: