当然还有其他方法可以做到这一点,但只是为了论证,如果我在下面的代码中将 EnumerateFiles() 替换为 GetFiles() ,使用 GetFiles() 似乎会提高性能,它> 1 秒。对于 10 个目录,每个目录包含 10 个文件,比 EnumerateFiles() 更快。
有人知道这是为什么吗?
这很有趣,因为我假设 EnumerateFiles() 由于延迟加载而更有效,而 GetFiles() 是旧式的处理方式。 微软只说 EnumerateFiles() 在处理大型集合时更有效,没有任何性能损失......
https://learn.microsoft.com/en-us/dotnet/api/system.io.directory.enumeratedirectories?view=net-8.0
这是因为文件复制操作尝试在不同位置读取和写入磁盘时,仍然枚举文件系统条目吗?那么磁头必须来回切换吗?看来有什么要注意的!
后续问题:这如何通过网络共享进行?
using System;
using System.IO;
// Copy all the files in source paths to target paths
foreach( string newPath in Directory.EnumerateFiles( masterRecordingsDirectory, "*.*", SearchOption.AllDirectories ) )
{
File.Copy( newPath, newPath.Replace( masterRecordingsDirectory, currentRecordingsDirectory ) );
}
编辑: 正如评论中的人们所指出的,这两种方法都在底层调用了InternalEnumeratePaths()。但重点是,Get 方法在返回之前首先转换为 List,而 Enumerate 开始生成路径,而其他方法仍在检索中。所以在我看来,问题仍然存在,哪种方法适合哪种情况? Microsoft 文档没有详细介绍这一点。
Edit2:我再次使用不同名称的文件/文件夹进行测试,以防止缓存丢弃结果。我仍然发现有利于 GetFiles()/GetDirectories() 的差异(尽管现在以毫秒为单位)。 还有更多的文件读取是针对 Enumerate(在 80 年代)而不是 GetFiles(在 50 年代),这似乎支持这些结果。 但请继续在上面打洞!
这是我的测试代码:
using System;
using System.IO;
using System.Linq;
internal class Program
{
static void Main(string[] args)
{
string baseDir = Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments), "Test2");
string sourceDir = Path.Combine(baseDir, "Source2");
string targetDir = Path.Combine(baseDir, "Target2");
Directory.CreateDirectory(baseDir);
Directory.CreateDirectory(sourceDir);
Directory.CreateDirectory(targetDir);
for (int i = 1; i < 10; i++)
{
Directory.CreateDirectory(Path.Combine(sourceDir, "Blah2" + i.ToString()));
}
foreach (var dir in Directory.GetDirectories(sourceDir))
{
for (int i = 1; i < 10; i++)
{
File.Create(Path.Combine(dir, "Blah2" + i.ToString()));
}
}
// Copy all the files in source paths to target paths
foreach (string newPath in Directory.GetFiles(sourceDir, "*.*", SearchOption.AllDirectories))
File.Copy(newPath, newPath.Replace(sourceDir, targetDir));
}
}
因此,我按照 @Charlieface 的建议使用 BenchmarkDotNet 来获得更精确的测试结果,并且我必须承认 EnumerateFiles() 是明显的赢家,本地调用速度快了 10 倍以上。对于网络上的结果,差异似乎更大,但我无法进行良好的测试,因为它运行的时间太长,因此测试套件因错误而中途停止。
本地文件操作结果:
作业=MediumRun工具链=InProcessNoEmitToolchain IterationCount=15
启动次数=1 预热次数=10
方法 | 意思是 | 错误 | 标准偏差 | 中位数 |
---|---|---|---|---|
列举 | 46.63 毫秒 | 8.663 毫秒 | 7.234 毫秒 | 43.00 毫秒 |
获取 | 607.26 毫秒 | 435.252 毫秒 | 407.135 毫秒 | 366.41 毫秒 |
免责声明:我关闭了所有其他窗口和进程,但可能仍然是测试不完美,Get 操作的 StdDev 相当高。虽然我运行了多次测试,但结果总是和上面类似。
据我所知,结论:使用 EnumerateFiles/Dirs 而不是 Get!