除 File.Move 之外的更快文件移动方法
本文关键字:文件 移动 方法 File Move | 更新日期: 2023-09-27 18:32:33
我有一个控制台应用程序,大约需要 625 天才能完成。 除非有办法让它更快。
首先,我在一个目录中工作,该目录包含大约 4,000,000 个文件(如果不是更多的话)。 我正在一个数据库中工作,该数据库每个文件都有一行,然后是一些。
现在使用 SQL 的速度相对较快,瓶颈是当我使用 File.Move()
每个移动需要 18 秒才能完成。
有没有比File.Move()
更快的方法?
这是瓶颈:
File.Move(Path.Combine(location, fileName), Path.Combine(rootDir, fileYear, fileMonth, fileName));
所有其他代码运行得非常快。 我需要做的就是将一个文件移动到新位置,然后更新数据库位置字段。
如果需要,我可以显示其他代码,但实际上以上是当前唯一的瓶颈。
事实证明,从File.Move切换到设置FileInfo并使用.MoveTo显着提高了速度。
它将在大约 35 天内运行,而不是 625 天。
FileInfo fileinfo = new FileInfo(Path.Combine(location, fileName));
fileinfo.MoveTo(Path.Combine(rootDir, fileYear, fileMonth, fileName));
18秒并不罕见。当您在单个目录中具有大量文件时,NTFS 的性能不佳。当您请求文件时,它必须对其目录数据结构进行线性搜索。对于 1,000 个文件,这不会花费太长时间。有了 10,000 个文件,您会注意到它。拥有 400 万个文件 . . .是的,这需要一段时间。
如果将所有目录条目预加载到内存中,则可能会更快地执行此操作。然后,无需为每个文件调用 FileInfo
构造函数,只需在字典中查找它即可。
像这样:
var dirInfo = new DirectoryInfo(path);
// get list of all files
var files = dirInfo.GetFileSystemInfos();
var cache = new Dictionary<string, FileSystemInfo>();
foreach (var f in files)
{
cache.Add(f.FullName, f);
}
现在,当您从数据库中获取名称时,只需在字典中查找即可。这可能比每次都尝试从磁盘获取它更快。
您可以并行移动文件,并且使用 Directory.EnumerateFiles
会给您一个延迟加载的文件列表(当然,我还没有用 4,000,000 个文件对其进行测试):
var numberOfConcurrentMoves = 2;
var moves = new List<Task>();
var sourceDirectory = "source-directory";
var destinationDirectory = "destination-directory";
foreach (var filePath in Directory.EnumerateFiles(sourceDirectory))
{
var move = new Task(() =>
{
File.Move(filePath, Path.Combine(destinationDirectory, Path.GetFileName(filePath)));
//UPDATE DB
}, TaskCreationOptions.PreferFairness);
move.Start();
moves.Add(move);
if (moves.Count >= numberOfConcurrentMoves)
{
Task.WaitAll(moves.ToArray());
moves.Clear();
}
}
Task.WaitAll(moves.ToArray());