C# 比file.move更快的文件移动方法

C# 比file.move更快的文件移动方法,c#,console-application,C#,Console Application,我有一个控制台应用程序,大约需要625天才能完成。除非有办法加快速度 首先,我在一个目录中工作,这个目录中有大约4000000个文件,如果不是更多的话。我在一个数据库中工作,每个文件都有一行,然后是一些 现在使用SQL的速度相对较快,瓶颈是当我使用File.Move()时,每次移动需要18秒才能完成 有没有比File.Move()更快的方法 这是瓶颈: File.Move(Path.Combine(location, fileName), Path.Combine(rootDir, fileYe

我有一个控制台应用程序,大约需要625天才能完成。除非有办法加快速度

首先,我在一个目录中工作,这个目录中有大约4000000个文件,如果不是更多的话。我在一个数据库中工作,每个文件都有一行,然后是一些

现在使用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的性能不好。当您请求一个文件时,它必须对其目录数据结构进行线性搜索。有1000个文件,这并不需要太长时间。你会注意到有10000个文件。有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);
}
var dirInfo=newdirectoryinfo(路径);
//获取所有文件的列表
var files=dirInfo.GetFileSystemInfos();
var cache=newdictionary();
foreach(文件中的var f)
{
cache.Add(f.FullName,f);
}

现在,当您从数据库中获得一个名称时,您可以在字典中查找它。这可能比每次尝试从磁盘获取文件要快。

您可以并行移动文件,也可以使用
目录。EnumerateFiles
提供了一个延迟加载的文件列表(当然,我没有用4000000个文件测试它):

var numberOfConcurrentMoves=2;
var moves=新列表();
var sourceDirectory=“sourceDirectory”;
var destinationDirectory=“目标目录”;
foreach(目录中的var filePath.EnumerateFiles(sourceDirectory))
{
var move=新任务(()=>
{
File.Move(filePath,Path.Combine(destinationDirectory,Path.GetFileName(filePath));
//更新数据库
},任务创建选项。首选公平性);
move.Start();
移动。添加(移动);
if(moves.Count>=numberOfConcurrentMoves)
{
Task.WaitAll(moves.ToArray());
移动。清除();
}
}
Task.WaitAll(moves.ToArray());

如果你使用的是数据库,为什么你需要4000000个文件?@TimSchmelter这是他们最初的设计方式。数据库包含文件中的一些信息。我需要更新的唯一部分是位置列。该列告诉应用程序他们使用文档所在的位置来打开文档。如果每次移动都需要18秒,那么其他方面就非常错误,可能不是您使用的API。可能是您感兴趣的原因@JamesWilson那么操作系统可能需要很长时间来更新包含的目录。我担心要进行测试,因为它需要将400万个文件加载到目录中,然后才能开始移动它们。如果我没有弄错的话,那么一旦它们在字典中,我仍然需要对文件执行File.Move或fileinfo.MoveTo()。@JamesWilson:是的,您仍然需要执行
fileinfo.MoveTo()
。其想法是,预加载所有条目将消除您必须逐个搜索它们的情况。我不知道400万条是否是内存问题。我也不知道加载需要多长时间,虽然我怀疑这将远远少于一个小时。结果是否会比你的35天快,我不确定。这是个好消息。不过,这样做似乎很奇怪。我可能得研究一下为什么会这样。@JimMischel是的,我已经测试了一整天了,速度已经和这么多文件一致了。我只能找到File.Move在每次调用时检查权限/安全性,其中fileInfo.MoveTo()只检查一次。如果你还有什么我想知道的,很奇怪。我没有找到任何速度改进:10529 ms(32824028 tiks)Directory.Move,13358 ms(41642456 tiks)new FileInfo().Move,10926 ms(34061807 tiks)File.Move()。它适用于16385个文件
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());