使用C#快速获取文件夹中包含大小的文件元数据的方法是什么? var myFileList=newlist(); var dir=newdirectoryinfo(@“C:\SomeDir”); foreach(dir.GetFiles()中的var文件) { 添加(新的MyCustomFileInfo() { Filename=file.Name, ModifiedOn=file.LastWriteTime, SizeInBytes=(int)file.Length }); }

使用C#快速获取文件夹中包含大小的文件元数据的方法是什么? var myFileList=newlist(); var dir=newdirectoryinfo(@“C:\SomeDir”); foreach(dir.GetFiles()中的var文件) { 添加(新的MyCustomFileInfo() { Filename=file.Name, ModifiedOn=file.LastWriteTime, SizeInBytes=(int)file.Length }); },c#,.net,C#,.net,dir.GetFiles执行得非常快,但当我开始访问属性时,似乎会对文件系统进行单独的调用(速度很慢) 如何重写此文件,以便以更有效的方式获取所有文件名、lastWriteTime和文件大小? 注意。 代码被简化为仅说明这一点。我的实际用例更复杂(一个同步的东西),但这是性能问题的核心。我想知道使用是否会更快 编辑: 我用dotPeek浏览了相关代码,所以可能看不到下面 无论哪种方式,如果您在Windows上部署,您都应该能够使用Win32本机函数的FindFirstFile系列,这就是.Len

dir.GetFiles执行得非常快,但当我开始访问属性时,似乎会对文件系统进行单独的调用(速度很慢)

如何重写此文件,以便以更有效的方式获取所有文件名、lastWriteTime和文件大小?

注意。 代码被简化为仅说明这一点。我的实际用例更复杂(一个同步的东西),但这是性能问题的核心。

我想知道使用是否会更快

编辑:

我用dotPeek浏览了相关代码,所以可能看不到下面

无论哪种方式,如果您在Windows上部署,您都应该能够使用Win32本机函数的
FindFirstFile
系列,这就是
.Length
等在封面下所做的(尽管正如您正确地假设的那样,它们对文件的完整路径执行
FindFirstFile
,并读取该文件,等等)

编辑2:


我再次查看了代码,它看起来确实应该用底层系统调用的数据填充FileInfos和DirectoryInfos。(您应该能够通过查看*Info上的
\u datainitialized
私有字段来验证这一点——如果为零,则初始化,如果为-1,则不初始化)。

在任何情况下,您都应该从循环继续测试条件中删除函数调用

var myFileList = new List<MyCustomFileInfo>();
var dir = new DirectoryInfo(@"C:\SomeDir");

foreach (var file in dir.GetFiles())
{
    myFileList.Add(new MyCustomFileInfo()
    {
        Filename = file.Name,
        ModifiedOn = file.LastWriteTime,
        SizeInBytes = (int)file.Length
    });
}
var myFileList=newlist();
var dir=newdirectoryinfo(@“C:\SomeDir”);
var files=dir.GetFiles();//只打了一次电话
foreach(文件中的var文件)
{
添加(新的MyCustomFileInfo()
{
Filename=file.Name,
ModifiedOn=file.LastWriteTime,
SizeInBytes=(int)file.Length
});
}

这是一种绝对正常的方法。如果速度慢,那么。。购买SSD或制作RAID(最好是SSD RAID^^)

如果“缓慢”导致的问题是不负责任的UI,那么请以非常简单的方式执行:只使用名称填充文件列表(这很快),然后运行一个线程,该线程将为列表中的每个项目获取额外数据。甚至可能使用虚拟列表仅获取当前显示的数据


另一件事可能是缓存最近的结果,因此,如果返回到上一个目录,结果将立即可用,而无需重新加载所有内容。

迭代文件夹中的所有文件本质上是一个缓慢的操作,无论底层存储是什么

在某些情况下,您可以通过使用而不是GetFiles并返回IEnumerable而不是数组或列表来提高性能。这样,如果使用Take()、Skip()、First()和其他可以在枚举所有内容之前返回的函数,就可以避免对所有文件进行迭代。您也可以使用Enumerable.Select将IEnumerable转换为您自己的类,尽管这会导致系统调用处理的每个文件

不幸的是,如果您想将当前文件系统状态与以前的快照进行比较,那么在同步场景中(这里的上下文非常重要),这将不起作用。在这种情况下,最好使用FileSystemWatcher等待对要同步的文件夹进行实际更改,然后再进行处理

一旦检测到文件夹中的更改,您可以在处理整个文件夹之前等待它们停止,或者保留所有更改事件的记录,并仅处理实际更改的文件。如果正在进行大量操作(例如,如果复制一个包含数千个文件的存储库),FileSystemWatcher可能会错过事件,但通常会收到文件以某种方式更改的通知

如果您确信您使用的是NTFS,事情就会变得更容易。在这种情况下,您可以启用日志记录,并获取自上次检查以来已更改的所有文件的列表。您还可以使用卷影服务读取甚至打开的文件,使用事务性NTFS以安全的方式修改文件等。这些功能需要本机调用,但项目提供了一个库

在内部,AlphaFS使用扩展方法来搜索文件,如。在Windows 7+中,此函数可以使用较大的缓冲区来提高性能


另一个好处是日志或NTFS的对象ID允许您检测重命名或文件移动(本质上是相同的),并避免不必要的文件同步。

哪个文件系统?您需要支持FAT还是NTFS才可以?我不确定是否/如何改进这一点(怀疑不是),但无论怎样,获取目录内容以外的任何信息都会影响性能。不完全确定,@ThomasW。在我的具体案例中,这是一个网络共享,但您可以用一种需要NTFS的通用方式来回答-如果对我不起作用,它可能会帮助其他人。:)嗯,网络共享很慢。。。有多少文件,你有多少ping时间?请尝试使用ping-l512来获得合理的数据量。在您的特定场景中,对所有文件的迭代不会有显著的改进。它也无法检测文件移动。唯一真正的改进是检测实际的变化,然后根据这些变化采取行动,这一点都没有帮助。GetFiles返回一个文件名数组,该数组是IEnumerable,因此foreach将在该数组上枚举。GetFiles无论哪种方式都只被调用一次。@CMircea但是如果您有n个文件,函数
GetFiles()
被调用n次,而IEnumerable被创建n次,不是吗?在我的解决方案中,它被称为1time@CMircea如果在循环运行时将文件添加到
dir
,会发生什么情况?我的版本不会在这个新文件上循环,而Kjensen版本
var myFileList = new List<MyCustomFileInfo>();
var dir = new DirectoryInfo(@"C:\SomeDir");
var files = dir.GetFiles(); // called 1 time only

foreach (var file in files)
{
    myFileList.Add(new MyCustomFileInfo()
    {
        Filename = file.Name,
        ModifiedOn = file.LastWriteTime,
        SizeInBytes = (int)file.Length
    });
}